/*-
 * Copyright (C) 2018-2020, Shanghai Trusted Industry Control Platform Co., Ltd.
 * Created by 周正辉 (Zhenghui Zhou) <zhouzhenghui@ticpsh.com>, 赵楷文 (Kaiwen
 * Zhao) <zhaokaiwen@ticpsh.com>
 */

#include <clang/AST/ParentMapContext.h>

#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>

#include "common/AttrAnalyzer.h"
#include "common/Coder.h"
#include "common/Searcher.h"
#include "testif.h"

using namespace clang;
using namespace std;
using namespace rocket::common;
using njson = nlohmann::json;
namespace fs = boost::filesystem;

static std::pair<std::string, bool> getLocation2Key(const std::string& path) {
  if (path.empty()) return make_pair("", false);
  fs::path fs_path = path;
  auto fs_relative = fs::relative(fs_path);

  fs_path = fs::weakly_canonical(path);

  if (fs_relative.begin()->filename().string() == "..") {
    return make_pair(fs_path.string(), false);
  }

  return make_pair("./" + fs::relative(fs_path).string(), true);
}

static std::pair<std::string, bool> getLocation2Key(const clang::Decl* decl) {
  auto& sm = decl->getASTContext().getSourceManager();
  return getLocation2Key(sm.getPresumedLoc(decl->getLocation()).getFilename());
}

std::string rocket::testif::TestIfConsumer::getFullIFTypeName(
    const clang::QualType& qt, clang::ASTContext& ast) {
  string type_name = rocket::common::getFullQTypeName(qt, ast);
  return currectKeyString(type_name);
}

string rocket::testif::TestIfConsumer::currectKeyString(string str) {
  // boost::replace_all(str, "$", "\uff04");
  // boost::replace_all(str, ".", "\uff0e");
  return str;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_init_string_literal(
    const QualType& type, const StringLiteral* sl, const string& type_name) {
  assert(!type.isRestrictQualified() && !type.isVolatileQualified());

  nlohmann::json j;
  j["@type"] = type_name;
  const ArrayType* array_type = type->getAsArrayTypeUnsafe();  // 字符串数组

  assert(array_type != NULL && array_type->getElementType()->isIntegerType());
  unsigned length;
  if (auto* ca = dyn_cast<const ConstantArrayType>(array_type)) {
    length =
        std::max(sl->getByteLength(), (unsigned)ca->getSize().getSExtValue());
  } else {
    length = sl->getByteLength();
  }
  j["@length"] = std::to_string(length);

  nlohmann::json value = nlohmann::json::array();
  std::string element_type =
      getFullIFTypeName(array_type->getElementType(), CI->getASTContext());
  for (unsigned i = 0; i < sl->getByteLength(); ++i) {
    nlohmann::json element;
    element["@type"] = element_type;
    element["@value"] = std::to_string(sl->getBytes()[i]);
    value.push_back(element);
  }
  j["@value"] = std::move(value);
  return j;
}

string rocket::testif::TestIfConsumer::parse_init_udliteral_expr(
    UserDefinedLiteral* udl) {
  string name = "user defined literal (at " +
                source_location_string(CI->getASTContext().getSourceManager(),
                                       udl->getBeginLoc()) +
                ")";
  assert(literals_j.find(name) == literals_j.end());

  nlohmann::json j;
  bool invalid = false;
  clang::Expr* cooked_literal = udl->getCookedLiteral();
  StringRef source = Lexer::getSourceText(
      CharSourceRange::getTokenRange(udl->getSourceRange()),
      CI->getASTContext().getSourceManager(), CI->getASTContext().getLangOpts(),
      &invalid);

  switch (udl->getLiteralOperatorKind()) {
    case UserDefinedLiteral::LiteralOperatorKind::LOK_Raw: {
      j["@kind"] = "Raw";
      j["@type"] = parse_type(cooked_literal->getType());
      j["@expr"] = invalid ? "" : source;
      break;
    }
    case UserDefinedLiteral::LiteralOperatorKind::LOK_Template: {
      j["@kind"] = "Template";
      j["@type"] = parse_type(cooked_literal->getType());
      j["@expr"] = invalid ? "" : source;
      //      j["@templateArgs"] = parse_template_args( udl.get);
      break;
    }
    case UserDefinedLiteral::LiteralOperatorKind::LOK_Integer: {
      j["@kind"] = "Integer";
      assert(cooked_literal);
      const IntegerLiteral* il = dyn_cast<IntegerLiteral>(cooked_literal);
      assert(il);
      j["@cookedtype"] = parse_type(cooked_literal->getType());
#if LLVM_VERSION_MAJOR < 13
      j["@cookedvalue"] = il->getValue().toString(10, true);
#else
      SmallString<10> S;
      il->getValue().toString(S, 10, true);
      j["@cookedvalue"] = S.str().str();
#endif
      j["@expr"] = invalid ? "" : source;
      break;
    }
    case UserDefinedLiteral::LiteralOperatorKind::LOK_Floating: {
      j["@kind"] = "Floating";
      assert(cooked_literal);
      const FloatingLiteral* fl = dyn_cast<FloatingLiteral>(cooked_literal);
      assert(fl);
      j["@cookedtype"] = parse_type(cooked_literal->getType());
      SmallVector<char, 16> str;
      string out;
      llvm::raw_string_ostream rso(out);
      fl->getValue().toString(str);
      rso << str;
      j["@cookedvalue"] = rso.str();
      j["@expr"] = invalid ? "" : source;
      break;
    }
    case UserDefinedLiteral::LiteralOperatorKind::LOK_String: {
      j["@kind"] = "String";
      assert(cooked_literal);
      const StringLiteral* sl = dyn_cast<StringLiteral>(cooked_literal);
      assert(sl);
      string type_name = j["@cookedtype"] =
          parse_type(cooked_literal->getType());
      j["@cookedvalue"] =
          parse_init_string_literal(cooked_literal->getType(), sl, type_name);
      j["@expr"] = invalid ? "" : source;
      break;
    }
    case UserDefinedLiteral::LiteralOperatorKind::LOK_Character: {
      j["@kind"] = "Character";
      assert(cooked_literal);
      const CharacterLiteral* cl = dyn_cast<CharacterLiteral>(cooked_literal);
      assert(cl);
      j["@cookedtype"] = parse_type(cooked_literal->getType());
      j["@cookedvalue"] = to_string(cl->getValue());
      j["@expr"] = invalid ? "" : source;
      break;
    }
  }
  j["@type"] = parse_type(udl->getType());
  j["@suffix"] = udl->getUDSuffix()->getName();

  elementCallBack(j);
  literals_j[name] = j;
  return name;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_init_list_struct(
    const RecordDecl* record, const InitListExpr* ile) {
  // assert(record->getParent()->isTranslationUnit());
  nlohmann::json j = nlohmann::json::object();
  auto field_it = record->field_begin();
  for (auto& e : ile->inits()) {
    std::string field_name =
        isCXX() ? getFullNDeclName(*field_it) : field_it->getNameAsString();
    QualType field_type = field_it->getType();
    if (!field_name.empty()) {
      j.emplace(std::move(field_name), parse_init_expr(field_type, e));
    } else if (field_type->isRecordType()) {
      njson anonymous_record = parse_init_expr(field_type, e);
      if (anonymous_record.is_string()) {
        j.emplace(std::move(field_name), anonymous_record);
      } else if (anonymous_record.is_object()) {
        auto anonymous_record_value_it = anonymous_record.find("@value");
        if (anonymous_record_value_it != anonymous_record.end()) {
          auto& value = anonymous_record_value_it.value();
          if (value.is_object()) {
            j.insert(value.begin(), value.end());
          }
        }
      }
    }
    field_it++;
  }
  return j;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_init_list_union(
    const InitListExpr* ile) {
  // assert(record->getParent()->isTranslationUnit());
  nlohmann::json j = nlohmann::json::object();
  for (auto& e : ile->inits()) {
    const FieldDecl* field_decl = ile->getInitializedFieldInUnion();
    std::string field_name = getFullNDeclName(field_decl);
    QualType field_type = field_decl->getType();
    if (!field_name.empty()) {
      j.emplace(std::move(field_name), parse_init_expr(field_type, e));
    } else if (field_type->isRecordType()) {
      njson anonymous_record = parse_init_expr(field_type, e);
      auto& value = anonymous_record["@value"];
      j.insert(value.begin(), value.end());
    }
  }
  return j;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_init_list_array(
    const ArrayType* type, const InitListExpr* ile) {
  nlohmann::json j = nlohmann::json::array();
  clang::QualType element_type = type->getElementType();
  for (auto& e : ile->inits()) {
    j.push_back(parse_init_expr(element_type, e));
  }
  return j;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_apvalue_array(
    const ArrayType* array_type, const APValue& apvalue) {
  nlohmann::json j = nlohmann::json::array();
  clang::QualType element_type = array_type->getElementType();

  // get the front length of code, e.g: get "aaa" size, but not "aaa/0" size
  unsigned size = apvalue.getArrayInitializedElts();
  static const int max_size = 50;

  size = size > max_size ? max_size : size;

  for (unsigned i = 0; i < size; ++i) {
    j.push_back(parse_apvalue(element_type, apvalue.getArrayInitializedElt(i)));
  }

  return j;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_apvalue_struct(
    const RecordDecl* record, const APValue& apvalue) {
  // assert(record->getParent()->isTranslationUnit());
  nlohmann::json j = nlohmann::json::object();
  auto field_it = record->field_begin();
  for (unsigned i = 0; i < apvalue.getStructNumFields(); ++i, ++field_it) {
    assert(field_it != record->field_end());
    const FieldDecl* field = *field_it;
    std::string field_name = getFullNDeclName(field);
    QualType field_type = field->getType();
    if (!field_name.empty()) {
      j.emplace(std::move(field_name),
                parse_apvalue(field_type, apvalue.getStructField(i)));
    } else if (field_type->isRecordType()) {
      njson anonymous_record =
          parse_apvalue(field_type, apvalue.getStructField(i));
      auto& value = anonymous_record["@value"];
      j.insert(value.begin(), value.end());
    }
  }

  nlohmann::json bases = nlohmann::json::object();
  if (const CXXRecordDecl* cxxrecord = dyn_cast<CXXRecordDecl>(record)) {
    auto base_it = cxxrecord->bases_begin();
    for (unsigned i = 0; i < apvalue.getStructNumBases(); ++i, ++base_it) {
      assert(base_it != cxxrecord->bases_end());
      const CXXBaseSpecifier& base = *base_it;

      bases[getFullIFTypeName(base.getType(), CI->getASTContext())] =
          parse_apvalue(base.getType(), apvalue.getStructBase(i));
    }
  }
  if (!bases.empty()) j["@bases"] = std::move(bases);

  return j;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_apvalue_union(
    const APValue& apvalue) {
  nlohmann::json j = nlohmann::json::object();
  const FieldDecl* field = apvalue.getUnionField();
  std::string field_name = field == nullptr ? "" : getFullNDeclName(field);
  QualType field_type = field == nullptr ? QualType() : field->getType();
  if (!field_name.empty()) {
    j.emplace(std::move(field_name),
              parse_apvalue(field_type, apvalue.getUnionValue()));
  } else if (!field_type.isNull() && field_type->isRecordType()) {
    njson anonymous_record = parse_apvalue(field_type, apvalue.getUnionValue());
    auto& value = anonymous_record["@value"];
    j.insert(value.begin(), value.end());
  }

  return j;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_apvalue_member_pointer(
    const APValue& apvalue) {
  // TODO:apvalue的成员指针如何表达？？？？
  nlohmann::json j = nlohmann::json::object();
  {
    nlohmann::json paths = nlohmann::json::array();
    const ArrayRef<const CXXRecordDecl*>& member_pointer_path =
        apvalue.getMemberPointerPath();
    for (const CXXRecordDecl* cxxrd : member_pointer_path) {
      paths.push_back(parse_cxxrecord_type(cxxrd));
    }
    j["@paths"] = std::move(paths);
  }

  {
    const ValueDecl* vd = apvalue.getMemberPointerDecl();
    if (vd) j["@name"] = getFullNDeclName(vd);
  }

  return j;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_scopes(
    const DeclContext* const dc, bool& hasFuncScope, bool& hasAnonymousScope) {
  nlohmann::json scopes = nlohmann::json::array();
  const DeclContext* tmp_dc = dc /*->getParent()*/;
  while (tmp_dc && !isa<TranslationUnitDecl>(tmp_dc)) {
    nlohmann::json scope = nlohmann::json::object();
    nlohmann::json& name = scope["@name"];
    nlohmann::json& kind = scope["@kind"] = nlohmann::json::array();

    if (const NamespaceDecl* nd = dyn_cast<NamespaceDecl>(tmp_dc)) {
      if (nd->isAnonymousNamespace()) {
        hasAnonymousScope = true;
      }
      name = getNamedDeclName(nd);
      scope["@fullname"] = getFullNDeclName(nd, false);
      kind.push_back(SCOPEKIND_STR[SCOPEKIND::SCOPE_NAMESPACE]);
      scopes.push_back(std::move(scope));
    } else if (const CXXRecordDecl* rd = dyn_cast<CXXRecordDecl>(tmp_dc)) {
      if (auto cxxtsd = dyn_cast<ClassTemplateSpecializationDecl>(rd)) {
        name = getNamedDeclName(rd) + common::getFullTempSpecArgsList(cxxtsd);
      } else {
        name = getNamedDeclName(rd);
      }
      kind.push_back(SCOPEKIND_STR[SCOPEKIND::SCOPE_RECORD]);
      // scope["@type"] = parse_type(clang::QualType(rd->getTypeForDecl(), 0));
      scope["@type"] = parse_cxxrecord_type(rd);
      scopes.push_back(std::move(scope));
    } /*else if (const CXXRecordDecl *rd = dyn_cast<CXXRecordDecl>(tmp_dc)) {
  }*/
    else if (const FunctionDecl* fd = dyn_cast<FunctionDecl>(tmp_dc)) {
      name = getNamedDeclName(fd);
      scope["@mangled"] = getFullNDeclName(fd, true);
      kind.push_back(SCOPEKIND_STR[SCOPEKIND::SCOPE_FUNCTION]);
      scopes.push_back(std::move(scope));
      hasFuncScope = true;
    } else if (const LinkageSpecDecl* lsd = dyn_cast<LinkageSpecDecl>(tmp_dc)) {
      switch (lsd->getLanguage()) {
#if LLVM_VERSION_MAJOR < 18
        case LinkageSpecDecl::LanguageIDs::lang_c:
#else
        case LinkageSpecLanguageIDs::C:
#endif
          name = "C";
          break;
#if LLVM_VERSION_MAJOR < 18
        case LinkageSpecDecl::LanguageIDs::lang_cxx:
#else
        case LinkageSpecLanguageIDs::CXX:
#endif
          name = "CXX";
          break;
      }
      kind.push_back(SCOPEKIND_STR[SCOPEKIND::SCOPE_LINKAGE]);
    } else if (const NamedDecl* nd = dyn_cast<NamedDecl>(tmp_dc)) {
      cerr << "Unknown scope decl: [" << getNamedDeclName(nd)
           << "] with DeclKind: [" << nd->getDeclKindName() << "]" << endl;
      name = getNamedDeclName(nd);
      kind.push_back(nd->getDeclName().getAsString());
      scopes.push_back(std::move(scope));
      hasFuncScope = true;
    } else {
      cerr << "Unknown scope DeclKind: [" << tmp_dc->getDeclKindName() << "]"
           << endl;
      name = "<UNKNOWN>";
      kind.push_back("<UNKNOWN>");
      scopes.push_back(std::move(scope));
      hasFuncScope = true;
    }

    if (isa<TemplateDecl>(tmp_dc)) {
      kind.push_back(SCOPEKIND_STR[SCOPEKIND::SCOPE_TEMPLATED]);
    }

    tmp_dc = tmp_dc->getParent();
  }
  return scopes;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_scopes(
    const DeclContext* const dc) {
  bool hasFuncScope;
  bool hasAnonymousScope;
  return parse_scopes(dc, hasFuncScope, hasAnonymousScope);
}

string rocket::testif::TestIfConsumer::parse_template_decl(
    const TemplateDecl* td) {
  if (!td) {
    throw "Unsupported Type:" + getNamedDeclName(td);
  }

  if (/*const BuiltinTemplateDecl *btd = dyn_cast*/ isa<BuiltinTemplateDecl>(
      td)) {
    // NOTE:used to implement __make_integer_seq and other builtin templates
    throw "Unsupported Type:" + getNamedDeclName(td);
  } else if (const RedeclarableTemplateDecl* rtd =
                 dyn_cast<RedeclarableTemplateDecl>(td)) {
    // redeclarable template
    if (const ClassTemplateDecl* ctd = dyn_cast<ClassTemplateDecl>(rtd)) {
      // 类模板的类型
      // return parse_type(
      //     clang::QualType(ctd->getTemplatedDecl()->getTypeForDecl(), 0));
      return parse_cxxrecord_type(ctd->getTemplatedDecl());
    } else if (const FunctionTemplateDecl* ftd =
                   dyn_cast<FunctionTemplateDecl>(rtd)) {
      // 函数模板，无法获取类
      throw "Unsupported Type:" + getNamedDeclName(ftd);
    } else if (const TypeAliasTemplateDecl* tatd =
                   dyn_cast<TypeAliasTemplateDecl>(rtd)) {
      // 别名模板 >=c++11
      return parse_type(
          clang::QualType(tatd->getTemplatedDecl()->getTypeForDecl(), 0));
    } else if (const VarTemplateDecl* vtd = dyn_cast<VarTemplateDecl>(rtd)) {
      // >=c++14
      return parse_type(vtd->getTemplatedDecl()->getType());
    }
  } else if (const TemplateTemplateParmDecl* ttpd =
                 dyn_cast<TemplateTemplateParmDecl>(td)) {
    // TODO:模板模板型参在内部使用时会成为匿名类型
    return "template-parameter-" + to_string(ttpd->getDepth()) + "-" +
           to_string(ttpd->getIndex());
  }

  return getFullNDeclName(td);
}

nlohmann::json rocket::testif::TestIfConsumer::parse_template_arg(
    const TemplateArgument& ta) {
  nlohmann::json ta_json = nlohmann::json::object();
  nlohmann::json& attributes = ta_json["@attributes"] =
      nlohmann::json ::array();
  switch (ta.getKind()) {
    case TemplateArgument::ArgKind::Null: {
      break;
    }
    case TemplateArgument::ArgKind::Type: {
      attributes.push_back("isTemplateArgType");
      ta_json["@type"] = parse_type(ta.getAsType());
      break;
    }
    case TemplateArgument::ArgKind::Declaration: {
      attributes.push_back("isTemplateArgDecl");
      ValueDecl* ta_vd = ta.getAsDecl();
      ta_json["@type"] = parse_type(ta_vd->getType());
      break;
    }
    case TemplateArgument::ArgKind::NullPtr: {
      attributes.push_back("isTemplateArgNullPtr");
      ta_json["@type"] = parse_type(ta.getNullPtrType());
      break;
    }
    case TemplateArgument::ArgKind::Integral: {
      ta_json =
          parse_apvalue(ta.getIntegralType(), APValue(ta.getAsIntegral()));
      ta_json["@type"] = parse_type(ta.getIntegralType());
      nlohmann::json& attributes = ta_json["@attributes"] =
          nlohmann::json ::array();
      attributes.push_back("isTemplateArgIntegral");
      break;
    }
    case TemplateArgument::ArgKind::Template: {
      attributes.push_back("isTemplateArgTemplate");
      const TemplateName& ta_tn = ta.getAsTemplate();
      if (const TemplateDecl* ta_td = ta_tn.getAsTemplateDecl()) {
        ta_json["@type"] = parse_template_decl(ta_td);
      } else {
        switch (ta_tn.getKind()) {
          case clang::TemplateName::Template: {
            TemplateDecl* ta_td = ta_tn.getAsTemplateDecl();
            assert(ta_td);
            // cppreference -- 模板模板一定是一个类型模板（c++17）或类模板
            if (ClassTemplateDecl* ta_ctd =
                    dyn_cast<ClassTemplateDecl>(ta_td)) {
              ta_json["@type"] = parse_type(

                  clang::QualType(ta_ctd->getTemplatedDecl()->getTypeForDecl(),
                                  0));
            } else {
              throw runtime_error(
                  "TemplateTemplate argument unknow type Template");
            }
            break;
          }
          case clang::TemplateName::OverloadedTemplate: {
            attributes.push_back("isOverloadedTemplate");
            throw runtime_error(
                "TemplateTemplate argument unknow type OverloadedTemplate");
            break;
          }
          case clang::TemplateName::QualifiedTemplate: {
            attributes.push_back("isQualifiedTemplate");
            TemplateDecl* ta_td =
                /*ta_tn.getAsQualifiedTemplateName()->getDecl()*/ nullptr;
            assert(ta_td);
            // cppreference -- 模板模板一定是一个类型模板（c++17）或类模板
            if (ClassTemplateDecl* ta_ctd =
                    dyn_cast<ClassTemplateDecl>(ta_td)) {
              // ta_json["@type"] = parse_type(clang::QualType(
              //    ta_ctd->getTemplatedDecl()->getTypeForDecl(), 0));
              ta_json["@type"] =
                  parse_cxxrecord_type(ta_ctd->getTemplatedDecl());
            } else {
              throw runtime_error(
                  "TemplateTemplate argument unknow type QualifiedTemplate");
            }
            break;
          }
          case clang::TemplateName::DependentTemplate: {
            attributes.push_back("isDependentTemplate");
            DependentTemplateName* ta_dtn = ta_tn.getAsDependentTemplateName();
            if (ta_dtn->isIdentifier()) {
              attributes.push_back("isIdentifier");
              ta_json["@type"] = ta_dtn->getIdentifier()->getNameStart();
            } else if (ta_dtn->isOverloadedOperator()) {
              attributes.push_back("isOverloadedOperator");
            } else {
              throw runtime_error(
                  "TemplateTemplate argument unknow type DependentTemplate");
            }
            break;
          }
          case clang::TemplateName::SubstTemplateTemplateParm: {
            attributes.push_back("isSubstTemplateTemplateParm");
            TemplateDecl* ta_td = ta_tn.getAsSubstTemplateTemplateParm()
                                      ->getParameter()
                                      ->getDescribedTemplate();
            assert(ta_td);
            // cppreference -- 模板模板一定是一个类型模板（c++17）或类模板
            if (ClassTemplateDecl* ta_ctd =
                    dyn_cast<ClassTemplateDecl>(ta_td)) {
              // ta_json["@type"] = parse_type(clang::QualType(
              //    ta_ctd->getTemplatedDecl()->getTypeForDecl(), 0));
              ta_json["@type"] =
                  parse_cxxrecord_type(ta_ctd->getTemplatedDecl());
            } else {
              throw runtime_error(
                  "TemplateTemplate argument unknow type "
                  "SubstTemplateTemplateParm");
            }
            break;
          }
          case clang::TemplateName::SubstTemplateTemplateParmPack: {
            attributes.push_back("isSubstTemplateTemplateParmPack");
            SubstTemplateTemplateParmPackStorage* ta_sttpps =
                ta_tn.getAsSubstTemplateTemplateParmPack();
            NamedDecl* ta_td =
                ta_sttpps->getParameterPack()->getTemplatedDecl();
            assert(ta_td);
            // cppreference --
            //          模板模板一定是一个类型模板（c++ 17）或类模板
            if (ClassTemplateDecl* ta_ctd =
                    dyn_cast<ClassTemplateDecl>(ta_td)) {
              // ta_json["@type"] = parse_type(clang::QualType(
              //    ta_ctd->getTemplatedDecl()->getTypeForDecl(), 0));
              ta_json["@type"] =
                  parse_cxxrecord_type(ta_ctd->getTemplatedDecl());
            } else {
              throw runtime_error(
                  "TemplateTemplate argument unknow type "
                  "SubstTemplateTemplateParmPack");
            }
            break;
          }
          default: {
            // AssumedTemplate, in >= clang 8.0.0
            std::cerr << "unsupported TemplateName Kind" << std::endl;
          }
        }
      }
      break;
    }
    case TemplateArgument::ArgKind::TemplateExpansion: {
      attributes.push_back("isTemplateArgTemplateExpansion");
      throw runtime_error("TemplateExpansion argument unknow type ");
      // a kind of Pack
      break;
    }
    case TemplateArgument::ArgKind::Expression: {
      attributes.push_back("isTemplateArgExpression");
      clang::Expr* ta_expr = ta.getAsExpr();
      ta_json["@type"] = parse_type(ta_expr->getType());
      // TODO: 此处Expression实际代表的代码未知
      break;
    }
    case TemplateArgument::ArgKind::Pack: {
      attributes.push_back("isTemplateArgPack");
      break;
    }
  }
  return ta_json;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_template_parms(
    const TemplateParameterList* tp_list) {
  nlohmann::json template_parms = nlohmann::json::array();
  for (const NamedDecl* tp : tp_list->asArray()) {
    nlohmann::json template_parm = nlohmann::json::object();
    nlohmann::json temp_attributes = nlohmann::json::array();

    if (tp->isTemplateParameterPack()) temp_attributes.push_back("isParmPack");

    if (const TemplateTypeParmDecl* ttpd = dyn_cast<TemplateTypeParmDecl>(tp)) {
      clang::QualType tp_qt = clang::QualType(ttpd->getTypeForDecl(), 0);
      template_parm["@name"] = getFullIFTypeName(tp_qt, CI->getASTContext());
      template_parm["@depth"] = to_string(ttpd->getDepth());
      template_parm["@index"] = to_string(ttpd->getIndex());
      template_parm["@type"] =
          getFullIFTypeName(tp_qt.getCanonicalType(), CI->getASTContext());
      if (ttpd->hasDefaultArgument()) {
#if LLVM_VERSION_MAJOR > 18
        template_parm["@default"] =
            parse_type(ttpd->getDefaultArgument().getArgument().getAsType());
#else
        template_parm["@default"] = parse_type(ttpd->getDefaultArgument());
#endif
      }
      temp_attributes.push_back("isTypeTemplateParm");
    } else if (const NonTypeTemplateParmDecl* nttpd =
                   dyn_cast<NonTypeTemplateParmDecl>(tp)) {
      template_parm["@type"] = parse_type(nttpd->getType());
      template_parm["@depth"] = to_string(nttpd->getDepth());
      template_parm["@index"] = to_string(nttpd->getIndex());
      template_parm["@name"] = getNamedDeclName(nttpd);
      if (nttpd->hasDefaultArgument()) {
#if LLVM_VERSION_MAJOR > 18
        template_parm["@default"] = parse_init_expr(
            nttpd->getType(),
            nttpd->getDefaultArgument().getArgument().getAsExpr());
#else
        template_parm["@default"] =
            parse_init_expr(nttpd->getType(), nttpd->getDefaultArgument());
#endif
      }
      temp_attributes.push_back("isNonTypeTemplateParm");
    } else if (const TemplateTemplateParmDecl* ttpd =
                   dyn_cast<TemplateTemplateParmDecl>(tp)) {
      template_parm["@name"] = getNamedDeclName(ttpd);
      template_parm["@depth"] = to_string(ttpd->getDepth());
      template_parm["@index"] = to_string(ttpd->getIndex());
      template_parm["@templatePrefix"] =
          common::makeTemplateParmList(ttpd->getTemplateParameters());
      template_parm["@templateParms"] =
          parse_template_parms(ttpd->getTemplateParameters());
      if (ttpd->hasDefaultArgument()) {
        template_parm["@default"] =
            parse_template_arg(ttpd->getDefaultArgument().getArgument());
      }

      temp_attributes.push_back("isTemplateTemplateParm");
    }

    template_parm["@attributes"] = std::move(temp_attributes);
    template_parms.push_back(std::move(template_parm));
  }
  return template_parms;
}

void rocket::testif::TestIfConsumer::parse_template_type_parm(
    const QualType& type, nlohmann::json& j) {
  if (const TemplateTypeParmType* ttpt = type->getAs<TemplateTypeParmType>()) {
    string typename_type_name =
        ttpt->getDecl()
            ? getFullNDeclName(ttpt->getDecl())
            : getFullIFTypeName(type.getCanonicalType(), CI->getASTContext());
    string type_name = "(typeparam[" + typename_type_name + "])";
    {
      j["@name"] = typename_type_name;
      j["@depth"] = to_string(ttpt->getDepth());
      j["@index"] = to_string(ttpt->getIndex());
      j["@attributes"] = njson::array({"isTypeTemplateParm", "isPlaceHolder"});
    }
  }
}

void rocket::testif::TestIfConsumer::parse_function_type(const QualType& type,
                                                         nlohmann::json& j) {
  std::string type_name = getFullIFTypeName(type, CI->getASTContext());

  {
    j["@name"] = type_name;

    nlohmann::json& attributes = j["@attributes"];
    attributes = nlohmann::json::array();
    attributes.push_back("isFunction");

    if (const FunctionProtoType* func_type = type->getAs<FunctionProtoType>()) {
      clang::QualType return_type = func_type->getReturnType();
      if (!return_type->isVoidType()) {
        j["%"]["@type"] = parse_type(return_type);
      }
      nlohmann::json params = nlohmann::json::array();
      int i = 0;
      for (auto it = func_type->param_type_begin(),
                e = func_type->param_type_end();
           it != e; ++it, ++i) {
        nlohmann::json param;
        param["@name"] = "_" + std::to_string(i);
        param["@type"] = parse_type(*it);
        params.push_back(param);
      }
      j["params"] = params;
      if (type.isConstQualified()) attributes.push_back("isConst");
      if (func_type->isVariadic()) attributes.push_back("isVariadic");
    } else {
      const FunctionNoProtoType* func_noproto_type =
          type->getAs<FunctionNoProtoType>();
      assert(func_noproto_type != NULL);
      clang::QualType return_type = func_noproto_type->getReturnType();
      if (!return_type->isVoidType()) {
        j["%"]["@type"] = parse_type(return_type);
      }
    }
  }
}

nlohmann::json rocket::testif::TestIfConsumer::parse_function_declaration(
    const FunctionDecl* func_decl, bool based_on_definition) {
  nlohmann::json testif;

  if (!func_decl) return testif;

  // 函数声明的使用位置记录
  unsigned path_count = 0;
  for (auto vd_rd : func_decl->redecls()) {
    if (vd_rd->getBeginLoc().isValid()) {
      current_file.push_back(CI->getASTContext().getSourceManager().getFileID(
          vd_rd->getBeginLoc()));
      path_count++;
    }
  }

  {
    // 增加参数和模板实参
    if (!isCXX()) {
      testif["@name"] = testif["name"] = func_decl->getNameAsString();
      testif["@nameargs"] = common::getFullFuncName(func_decl, false, true);
    } else {
      testif["@name"] = testif["name"] = testif["@nameargs"] =
          common::getFullFuncName(func_decl, false, true);
    }
    testif["@fullname"] = common::getFullFuncName(func_decl, true, true);
    testif["@mangled"] = getFullNDeclName(func_decl, true);
    testif["@attributes"] = getFuncAttrs(func_decl);
  }

  // 模板函数/模板类方法原型
  {
    FunctionDecl* func_orign = nullptr;
    FunctionTemplateDecl* func_template = nullptr;

    if (func_decl->isTemplateDecl()) {
      func_template = func_decl->getDescribedFunctionTemplate();
    } else if (func_decl->isFunctionTemplateSpecialization()) {
      func_orign = func_decl->getPrimaryTemplate()->getTemplatedDecl();
      func_template = func_orign->getDescribedFunctionTemplate();
    }

    // func_orign
    if (func_decl->getMemberSpecializationInfo()) {
      func_orign = llvm::dyn_cast<clang::FunctionDecl>(
          func_decl->getMemberSpecializationInfo()->getInstantiatedFrom());
    } else if (func_template) {
      if (auto ift = func_template->getInstantiatedFromMemberTemplate()) {
        func_orign = ift->getTemplatedDecl();
      }
    }

    if (func_orign && func_orign != func_decl) {
      testif["@templateDescribed"] = common::getFullNDeclName(func_orign, true);
    }
    if (func_template) {
      testif["@template"] =
          common::getFullNDeclName(func_template->getTemplatedDecl(), true);
    }

    // 依赖模板原型获取文件位置
    auto func_loc_decl =
        func_decl->getDefinition() ? func_decl->getDefinition() : func_decl;
    if (func_orign) {
      if (func_orign->getDefinition()) {
        if ((func_decl->getTemplateSpecializationInfo() &&
             func_decl->getTemplateSpecializationInfo()
                 ->isExplicitInstantiationOrSpecialization()) ||
            (func_decl->getMemberSpecializationInfo() &&
             func_decl->getMemberSpecializationInfo()
                 ->isExplicitSpecialization())) {
          // 显示特化保持本身定位
        } else {
          func_loc_decl = func_orign->getDefinition();
        }
      }
    }

    njson location = njson::object();
    {
      njson begin = njson::object();
      PresumedLoc presumed_loc =
          CI->getASTContext().getSourceManager().getPresumedLoc(
              func_loc_decl->getBeginLoc());
      begin["line"] = std::to_string(presumed_loc.getLine());
      begin["column"] = std::to_string(presumed_loc.getColumn());
      location["begin"] = std::move(begin);
      if (setting.analyze_level !=
          share::RocketAnalyzeSetting::AnalyzeLevel::AL_Local) {
        auto func_def_loc = func_loc_decl;

        auto loc_key = getLocation2Key(func_def_loc);
        location["path"] = loc_key.first;
        location["isInProjectFile"] = loc_key.second;
        location["isInMainFile"] =
            CI->getASTContext().getSourceManager().isInMainFile(
                func_loc_decl->getLocation());
      }
    }
    {
      njson end = njson::object();
      PresumedLoc presumed_loc =
          CI->getASTContext().getSourceManager().getPresumedLoc(
              func_loc_decl->getEndLoc());
      end["line"] = std::to_string(presumed_loc.getLine());
      end["column"] = std::to_string(presumed_loc.getColumn());
      location["end"] = std::move(end);
    }
    testif["location"] = std::move(location);
  }

  // 为模板函数时
  if (FunctionTemplateDecl* func_template =
          func_decl->getDescribedFunctionTemplate()) {
    testif["@templateParms"] =
        parse_template_parms(func_template->getTemplateParameters());
  } else if (auto tsa =
                 func_decl
                     ->getTemplateSpecializationArgs()) {  // 为模板函数特化时
    testif["@templateArgs"] = parse_template_args(tsa);
  }

  {
    njson& output_ret = testif["output"]["%"] = njson::object();
    if (auto ctor_decl = dyn_cast<CXXConstructorDecl>(func_decl)) {
      output_ret["@type"] =
          parse_type(QualType(ctor_decl->getParent()->getTypeForDecl(), 0));
    } else {
      clang::QualType return_type = func_decl->getReturnType();
      if (!return_type->isVoidType()) {
        output_ret["@type"] = parse_type(return_type);
      }
    }
  }

  {  // 函数边界
    nlohmann::json scopes = parse_scopes(func_decl->getDeclContext());
    if (!scopes.empty()) {
      testif["@scopes"] = std::move(scopes);
    }
  }

  {
    // 函数形参
    nlohmann::json params = nlohmann::json::object();
    //  nlohmann::json output_params = nlohmann::json::object();
    int index = 0;
    auto decl_params = based_on_definition && func_decl->getDefinition()
                           ? func_decl->getDefinition()
                           : func_decl;
    for (FunctionDecl::param_const_iterator it = decl_params->param_begin(),
                                            e = decl_params->param_end();
         it != e; ++it, ++index) {
      std::string param_name = (std::string)(*it)->getName();
      param_name = (param_name == "" ? ("_" + to_string(index)) : param_name);

      clang::QualType param_type = (*it)->getType();
      params[param_name]["@type"] = parse_type(param_type);
      params[param_name]["@index"] = std::to_string(index);
      //    filter_output_params(output_params, param_name, param_type);

      ParmVarDecl* def = *it;
      if (def && def->hasInit()) {
        clang::Expr* init = def->getInit();
        // const clang::APValue* apvalue = def->evaluateValue();
        // if (apvalue) {
        // params[param_name]["@default"] = parse_apvalue(param_type, *apvalue);
        // } else
        {
          // NOTE:
          // 出现def->evaluateValue()内部出现崩溃错误，疑似由于函数参数特殊初始化赋值导致的问题。
          // 目前由于改情况内容不计入testif报文，暂时关闭。
          params[param_name]["@default"] = parse_init_expr(param_type, init);
        }
        bool invalid = false;
        StringRef source = Lexer::getSourceText(
            CharSourceRange::getTokenRange(init->getSourceRange()),
            CI->getASTContext().getSourceManager(),
            CI->getASTContext().getLangOpts(), &invalid);
        if (!invalid &&
            source.str() != params[param_name]["@default"]["@value"]) {
          params[param_name]["@default"]["@expr"] = source;
        }
      }
    }
    if (!params.empty()) {
      testif["variables"]["params"] = std::move(params);
    }
  }

  // 动态异常
  auto ft = func_decl->getType()->castAs<clang::FunctionType>();
  if (auto fpt = dyn_cast<FunctionProtoType>(ft)) {
    for (auto dyn_throw : fpt->exceptions()) {
      testif["@dynExceptions"].push_back(
          getFullIFTypeName(dyn_throw, func_decl->getASTContext()));
    }
  }

  // 函数声明的使用位置记录弹出
  while (path_count != 0 && !current_file.empty()) {
    current_file.pop_back();
    path_count--;
  }

  return testif;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_function_stub(
    const FunctionDecl* func_decl /*, bool isDirect*/) {
  nlohmann::json stub = nlohmann::json::object();

  if (func_decl->isDefined()) {
    func_decl = func_decl->getDefinition();
  }

  {
    stub["@name"] = /*isDirect ?*/ func_decl->getNameAsString()
        /*: func_decl->getQualifiedNameAsString()*/;
    stub["@nameargs"] = common::getFullFuncName(func_decl, false, true);
  }

  stub["@fullname"] = common::getFullFuncName(func_decl, true, true);
  stub["@mangled"] = getFullNDeclName(func_decl, true);
  stub["@attributes"] = getFuncAttrs(func_decl);

  // stub["@type"] = parse_type(func_decl->getType());

  const clang::QualType return_type = func_decl->getReturnType();
  if (!return_type->isVoidType()) {
    stub["%"]["@type"] = parse_type(return_type);
  }

  // 桩函数模板
  nlohmann::json template_args =
      parse_template_args(func_decl->getTemplateSpecializationArgs());
  if (!template_args.empty()) {
    stub["@templateArgs"] = std::move(template_args);
  }

  // 模板函数/模板类方法原型
  {
    FunctionDecl* func_orign = nullptr;
    FunctionTemplateDecl* func_template = nullptr;

    if (func_decl->isTemplateDecl()) {
      func_template = func_decl->getDescribedFunctionTemplate();
    } else if (func_decl->isFunctionTemplateSpecialization()) {
      if (func_decl->getPrimaryTemplate()) {
        func_orign = func_decl->getPrimaryTemplate()->getTemplatedDecl();
        func_template = func_orign->getDescribedFunctionTemplate();
      }
    }

    // func_orign
    if (func_decl->getMemberSpecializationInfo()) {
      func_orign = llvm::dyn_cast<clang::FunctionDecl>(
          func_decl->getMemberSpecializationInfo()->getInstantiatedFrom());
    } else if (func_template) {
      if (auto ift = func_template->getInstantiatedFromMemberTemplate()) {
        func_orign = ift->getTemplatedDecl();
      }
    }

    if (func_orign && func_orign != func_decl) {
      stub["@templateDescribed"] = common::getFullNDeclName(func_orign, true);
    }
    if (func_template) {
      stub["@template"] =
          common::getFullNDeclName(func_template->getTemplatedDecl(), true);
    }
  }

  {  // 桩函数参数
    nlohmann::json& params = stub["params"] = nlohmann::json::array();
    unsigned param_name_count = 0;
    set<string> param_names;
    for (FunctionDecl::param_const_iterator it = func_decl->param_begin(),
                                            e = func_decl->param_end();
         it != e; ++it) {
      nlohmann::json param;
      auto& param_decl = *it;

      param["@type"] = parse_type(param_decl->getType());
      std::string name = (std::string)param_decl->getName();

      if (!name.empty()) {
        if (param_names.count(name)) {
          name += "_" + to_string(param_name_count);
        }
        param_names.insert(name);
        param["@name"] = std::move(name);
        ++param_name_count;
      }
      params.emplace_back(param);
    }
    if (param_name_count < func_decl->getNumParams()) {
      std::string prefix = "_";
      for (auto& param : params) {
        if (param["@name"].is_string()) {
#if LLVM_VERSION_MAJOR > 18
          while (
              StringRef(param["@name"].get<std::string>()).starts_with(prefix))
            prefix.append("_");
#else
          while (
              StringRef(param["@name"].get<std::string>()).startswith(prefix))
            prefix.append("_");
#endif
        }
      }
      unsigned i = 0;
      for (auto it = params.begin(); it != params.end(); ++it, ++i) {
        if (it.value()["@name"].is_null()) {
          it.value()["@name"] = prefix + std::to_string(i);
        }
      }
    }

    {
      string nameparams = common::getFullFuncName(func_decl, true, false) + "(";
      for (auto it = params.begin(); it != params.end(); ++it) {
        nameparams += it.value()["@type"].get<string>() + " " +
                      it.value()["@name"].get<string>() + ",";
      }
      if ((*nameparams.rbegin()) == ',') {
        nameparams.pop_back();
      }
      nameparams.append(")");
      stub["@nameparams"] = std::move(nameparams);
    }
  }

  {  // 桩函数边界
    nlohmann::json scopes = parse_scopes(func_decl->getDeclContext());
    if (!scopes.empty()) {
      stub["@scopes"] = std::move(scopes);
    }
  }

  // 桩函数为类成员时
  if (const CXXMethodDecl* cxxmd = dyn_cast<CXXMethodDecl>(func_decl)) {
    stub["@object"] =
        parse_type(QualType(cxxmd->getParent()->getTypeForDecl(), 0));
  }

  //  {
  //    string key_name = getFullNDeclName(func_decl, isCXX());
  //    auto dec_it = functiondecls_j.find(key_name);
  //    if (dec_it == functiondecls_j.end()) {
  //      njson stub_copy = stub;
  //      elementCallBack(stub_copy);
  //      functiondecls_j[key_name] = stub_copy;
  //    }
  //  }

  return stub;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_function_method(
    const FunctionDecl* func_decl) {
  return parse_function_stub(func_decl /*, true*/);
}

void rocket::testif::TestIfConsumer::parse_noprototype_function_stub(
    const FunctionDecl* func_decl, const CallExpr* call_expr,
    nlohmann::json& stubs, bool isDirect) {
  string func_name = getFullNDeclName(func_decl, isCXX());
  auto stub_it = stubs.find(func_name);
  if (stub_it == stubs.end()) {
    njson stub;

    if (isDirect)
      stub["@name"] = isCXX() ? func_decl->getNameAsString()
                              : common::getFullFuncName(func_decl, true, true);
    else
      stub["@name"] = func_decl->getQualifiedNameAsString();

    stub["@mangled"] = getFullNDeclName(func_decl, true);
    stub["@isCall"] = 1;

    QualType return_type = func_decl->getReturnType();
    // assert(return_type->isIntegerType());
    stub["%"]["@type"] = parse_type(return_type);
    njson attributes = getFuncAttrs(func_decl);
    attributes.push_back("noProtoType");
    stub["@attributes"] = std::move(attributes);
    njson params = njson::array();
    unsigned param_name_count = 0;
    for (auto arg : call_expr->arguments()) {
      njson param;
      param["@type"] =
          types_j[types_j[parse_type(arg->getType())]["@unqualified"]
                      .get<std::string>()]["@canonical"];
      param["@name"] = "_" + std::to_string(param_name_count++);
      params.emplace_back(std::move(param));
    }
    stub.emplace("params", std::move(params));
    stubs.emplace(std::move(func_name), std::move(stub));
  } else {
    njson& params = (*stub_it)["params"];
    unsigned min_num_args = params.size();
    if (min_num_args != call_expr->getNumArgs()) {
      njson& attributes = (*stub_it)["@attributes"];
      if (!isContainAttr(attributes, "isVariadic")) {
        attributes.emplace_back("isVariadic");
      }
      if (min_num_args > call_expr->getNumArgs()) {
        min_num_args = call_expr->getNumArgs();
        params.erase(params.begin() + min_num_args, params.end());
      }
    }
    for (unsigned i = 0; i < min_num_args; ++i) {
      std::string param_type = params[i]["@type"];
      std::string arg_type =
          types_j[types_j[parse_type(call_expr->getArg(i)->getType())]
                         ["@unqualified"]
                             .get<std::string>()]["@canonical"];
      if (param_type != arg_type) {
        const njson& param_attributes = types_j[param_type]["@attributes"];
        const njson& arg_attributes = types_j[arg_type]["@attributes"];
        if (isContainAttr(param_attributes, "isPointer") &&
            isContainAttr(arg_attributes, "isPointer")) {
          // 不同指针实参类型，形式参数类型采用void *
          std::string param_pointee_type = types_j[param_type]["@pointeeType"];
          std::string arg_pointee_type = types_j[arg_type]["@pointeeType"];
          if (isContainAttr(types_j[param_pointee_type]["@attributes"],
                            "isConst") ||
              isContainAttr(types_j[arg_pointee_type]["@attributes"],
                            "isConst")) {
            if (types_j[param_pointee_type]["@unqualified"]
                    .get<std::string>() ==
                types_j[arg_pointee_type]["@unqualified"].get<std::string>()) {
              if (isContainAttr(types_j[arg_pointee_type]["@attributes"],
                                "isConst")) {
                params[i]["@type"] = std::move(arg_type);
              }
            } else {
              params[i]["@type"] =
                  parse_type(CI->getASTContext().getPointerType(
                      CI->getASTContext().getConstType(
                          CI->getASTContext().VoidTy)));
            }
          } else {
            params[i]["@type"] = parse_type(CI->getASTContext().VoidPtrTy);
          }
        } else if (isContainAttr(param_attributes, "isReal") &&
                   isContainAttr(arg_attributes, "isReal")) {
          if (isContainAttr(param_attributes, "isInteger") &&
              isContainAttr(arg_attributes, "isInteger")) {
            std::string type_sign = "";
            if (param_type.find("unsigned") != param_type.npos &&
                arg_type.find("unsigned") != arg_type.npos) {
              type_sign = "unsigned ";
            }
            if (param_type.find("long long") != param_type.npos ||
                arg_type.find("long long") != arg_type.npos) {
              params[i]["@type"] = std::move(type_sign) + "long long";
            } else if (param_type.find("long") != param_type.npos ||
                       arg_type.find("long") != arg_type.npos) {
              params[i]["@type"] = std::move(type_sign) + "long";
            } else {
              params[i]["@type"] = std::move(type_sign) + "int";
            }
          } else if (isContainAttr(param_attributes, "isFloating") &&
                     isContainAttr(arg_attributes, "isFloating")) {
            if (param_type.find("long double") != param_type.npos ||
                arg_type.find("long double") != arg_type.npos) {
              params[i]["@type"] = "long double";
            } else if (param_type.find("double") != param_type.npos ||
                       arg_type.find("double") != arg_type.npos) {
              params[i]["@type"] = "double";
            } else {
              params[i]["@type"] = "float";
            }
          } else {
            if (param_type.find("long double") != param_type.npos ||
                arg_type.find("long double") != arg_type.npos) {
              params[i]["@type"] = "long double";
            } else if (param_type.find("long long") != param_type.npos ||
                       arg_type.find("long long") != arg_type.npos) {
              params[i]["@type"] = "long long";
            } else {
              params[i]["@type"] = "double";
            }
          }
        } else {
          min_num_args = i;
          params.erase(params.begin() + i, params.end());
          njson& attributes = (*stub_it)["@attributes"];
          if (!isContainAttr(attributes, "isVariadic")) {
            attributes.emplace_back("isVariadic");
          }
        }
      }
    }
  }
}

void rocket::testif::TestIfConsumer::add_using_global(
    njson& use_globals, const std::string& var_name, const njson& global,
    njson& test_if) {
  if (use_globals.find(var_name) != use_globals.end()) return;
  njson& j = use_globals.emplace(var_name, njson::object()).first.value();
  j["@type"] = global["@type"];
  j["@attributes"] = global["@attributes"];

  auto value_it = global.find("@value");
  if (value_it != global.end()) {
    j["@value"] = value_it.value();
  }

  auto gstubs_it = global.find("stubs");
  if (gstubs_it != global.end()) {
    auto& global_stubs = gstubs_it.value();

    if (test_if.find("stubs") == test_if.end()) {
      test_if["stubs"] = njson::object();
    }
    auto& stubs = test_if["stubs"];

    for (auto stub_it = global_stubs.begin(); stub_it != global_stubs.end();
         ++stub_it) {
      if (stubs.find(stub_it.key()) == stubs.end()) {
        stubs[stub_it.key()] = stub_it.value();
      }
    }

    for (auto& var : global["globals"]) {
      const std::string& name = var.get<std::string>();
      if (name == var_name) continue;
      auto it = globals_j.find(name);
      if (it == globals_j.end()) continue;
      add_using_global(use_globals, name, it.value(), test_if);
    }
  }
}

nlohmann::json rocket::testif::TestIfConsumer::parse_function_definition(
    FunctionDecl* func_decl, TargetFunction& target_func) {
  nlohmann::json testif = parse_function_declaration(func_decl, true);

  if (!func_decl) return testif;

  {
    nlohmann::json scopes = parse_scopes(func_decl->getDeclContext());
    if (!scopes.empty()) {
      testif["@scopes"] = std::move(scopes);
    }
  }

  if (func_decl->getDefinition()) {
    func_decl = func_decl->getDefinition();
  }

  // 函数定义的使用位置记录
  if (func_decl->getBeginLoc().isValid()) {
    current_file.push_back(CI->getASTContext().getSourceManager().getFileID(
        func_decl->getBeginLoc()));
  }

  if (setting.analyze_line_statistic) {
    auto& sm = CI->getASTContext().getSourceManager();
    if (func_decl && func_decl->getSourceRange().isValid() &&
        sm.isInMainFile(func_decl->getSourceRange().getBegin()) &&
        sm.isInMainFile(func_decl->getSourceRange().getEnd())) {
      auto func_range = func_decl->getSourceRange();
      auto func_begin = func_range.getBegin();
      auto func_end = func_range.getEnd();
      auto func_pbegin = sm.getPresumedLoc(func_begin);
      auto func_pend = sm.getPresumedLoc(func_end);

      auto func_begin_line = func_pbegin.getLine();
      auto func_end_line =
          func_pend.getLine() + 1;  // 加1保证最后一行也在统计范围内

      std::set<unsigned> code_lines;
      {
        auto code_line_it =
            codeline_info.code_lines.emplace(func_begin_line, 0).first;
        auto code_line_end =
            codeline_info.code_lines.emplace(func_end_line, 0).first;
        for (; code_line_it != code_line_end; ++code_line_it) {
          if (code_line_it->second == 0) continue;
          code_lines.insert(code_line_it->first);
        }
      }

      std::set<unsigned> comment_lines;
      {
        auto comment_line_it =
            codeline_info.comment_lines.emplace(func_begin_line, 0).first;
        auto loc_end =
            codeline_info.comment_lines.emplace(func_end_line, 0).first;
        for (; comment_line_it != loc_end; ++comment_line_it) {
          if (comment_line_it->second == 0) continue;
          comment_lines.insert(comment_line_it->first);
        }
      }

      std::set<unsigned> not_blank_lines(code_lines);
      not_blank_lines.insert(comment_lines.begin(), comment_lines.end());

      auto& code_info_j = testif["lineStatistic"] = njson::object();
      code_info_j["code"] = to_string(code_lines.size());
      code_info_j["comment"] = to_string(comment_lines.size());
      code_info_j["blank"] =
          to_string(func_end_line - func_begin_line - not_blank_lines.size());
      code_info_j["total"] = to_string(func_end_line - func_begin_line);
    }
  }

  //  TestIfVisitor tiv(func_decl->getASTContext(), target_func);
  //  tiv.TraverseDecl(func_decl);

  //  for (auto param : func_decl->parameters()) {
  //    tiv.TraverseDecl(param);
  //  }

  //  target_func.fixed_addresses = tiv.fixed_addresses;

  {
    // 函数内类型
    for (auto type_in_func : target_func.types) {
      parse_type(type_in_func);
    }
  }

  set<FunctionDecl*> stub_default_functions;
  {  // 桩函数
     // TODO: Add call sites/stubs
    set<FunctionDecl*> stub_functions;
    set<FunctionDecl*> stub_call_functions;
    nlohmann::json stubs = nlohmann::json::object();
    for (CallExpr* ce : target_func.stubs) {
      clang::FunctionDecl* call_decl = ce->getDirectCallee();
      if (call_decl) {
        if (call_decl->getNameAsString().compare(0, sizeof("__builtin") - 1,
                                                 "__builtin") == 0) {
          continue;  // __builtin函数
        } else if (auto method = dyn_cast<CXXMethodDecl>(call_decl)) {
          if (method->getParent() == CI->getASTContext().getVaListTagDecl())
            continue;
        }

        if (call_decl->getType()->getAs<FunctionNoProtoType>()) {
          parse_noprototype_function_stub(call_decl, ce, stubs, false);
        } else {
          stub_functions.insert(call_decl /*->getFirstDecl()*/);
          stub_call_functions.insert(call_decl->getFirstDecl());
        }
      }

      for (auto args : ce->arguments()) {
        parse_type(args->getType());
      }
    }
    for (clang::FunctionDecl* func_decl : target_func.funcs) {
      if (func_decl->getNameAsString().compare(0, sizeof("__builtin") - 1,
                                               "__builtin") == 0) {
        continue;  // __builtin函数
      } else if (auto method = dyn_cast<CXXMethodDecl>(func_decl)) {
        if (method->getParent() == CI->getASTContext().getVaListTagDecl())
          continue;
      }
      stub_functions.insert(func_decl->getFirstDecl());
    }
    for (const CXXConstructExpr* ctor : target_func.ctors) {
      auto cxxrd = ctor->getConstructor()->getParent();
      if (cxxrd == CI->getASTContext().getVaListTagDecl()) {
        continue;
      }
      stub_functions.insert(ctor->getConstructor() /*->getFirstDecl()*/);
      stub_call_functions.insert(ctor->getConstructor()->getFirstDecl());
    }

    for (auto stub_decl : stub_functions) {
      if (stub_decl->isImplicit()) {
        if (auto ctor_decl = dyn_cast<CXXConstructorDecl>(stub_decl)) {
          if (auto inher_decl =
                  ctor_decl->getInheritedConstructor().getConstructor()) {
            stub_decl = inher_decl;
          } else {
            continue;
          }
        } else if (auto method_decl = dyn_cast<CXXMethodDecl>(stub_decl)) {
          if (method_decl->isOverloadedOperator() &&
              method_decl->getOverloadedOperator() ==
                  OverloadedOperatorKind::OO_Equal) {
            stub_decl = method_decl;
          } else {
            continue;
          }
        } else {
          continue;
        }
      }
      string func_name = getFullNDeclName(stub_decl, isCXX());
      if (stub_decl->isDefaulted()) {
        if (stub_decl->getBody()) {
          stub_default_functions.insert(stub_decl);
        }
        continue;
      }
      if ((!setting.constexpr_is_stub && stub_decl->isConstexpr()) ||
          isInExcludeNamespace(stub_decl)) {
        // 编译器生成的函数不作为桩函数
        continue;
      }
      if (stubs.find(func_name) != stubs.end()) {
        continue;
      }
      if (auto method_decl = dyn_cast<CXXMethodDecl>(stub_decl)) {
        if (method_decl->getParent()->isLocalClass()) {
          // 局部类的方法函数不作为桩函数
          continue;
        }
      }

      auto& stub_func_j = stubs[func_name] =
          parse_function_stub(stub_decl /*, false*/);
      if (stub_call_functions.count(stub_decl->getFirstDecl())) {
        stub_func_j["@isCall"] = 1;
      }

      if (auto stub_method_decl = dyn_cast<CXXMethodDecl>(stub_decl)) {
        auto decl_it = function_declarations.find(stub_decl->getFirstDecl());
        if (decl_it != function_declarations.end()) {
          for (auto stub_decl : decl_it->second.overridings) {
            string func_name = getFullNDeclName(stub_decl, isCXX());

            if (stubs.find(func_name) != stubs.end()) continue;
            stubs[func_name] = parse_function_stub(stub_decl /*, false*/);
          }
        }

        for (auto over : stub_method_decl->overridden_methods()) {
          if (function_declarations.count(over->getFirstDecl())) {
            string func_name = getFullNDeclName(over, isCXX());

            if (stubs.find(func_name) != stubs.end()) continue;
            stubs[func_name] = parse_function_stub(over /*, false*/);
          }
        }
      }
    }

    testif["stubs"] = std::move(stubs);
  }

  {  // 局部静态变量
    njson statics = njson::object();
    for (unsigned int i = 0; i < target_func.statics.size(); ++i) {
      VarDecl* var = target_func.statics[i];
      njson j = parse_variable(var, false);
      j["@name"] = var->getName();
      statics[std::to_string(i)] = std::move(j);
    }
    if (!statics.empty()) {
      testif["variables"]["statics"] = statics;
      testif["output"]["statics"] = statics;
    }
  }

  // 函数绝对地址
  {
    njson fixed_addrs = njson::object();
    fixed_addrs["exprs"] = parse_fixed_address_exprs(
        target_func.fixed_addresses, CI->getASTContext());
    testif["fixedAddrs"] = std::move(fixed_addrs);
  }

  {  // 全局变量
    nlohmann::json use_globals = nlohmann::json::object();
    for (auto* var : target_func.globals) {
      std::string var_name = getFullNDeclName(var /*, true*/);
      auto it = globals_j.find(var_name);
      if (it != globals_j.end()) {
        add_using_global(use_globals, var_name, it.value(), testif);
      } else {
        use_globals[var_name] = parse_variable(var, false);
      }
    }

    if (!use_globals.empty()) {
      testif["variables"]["global"] = use_globals;
      testif["output"]["global"] = use_globals;
    }
  }

  {
    // 所属类
    // NOTE: output中的所属类由于用例结构的改变不再作为默认的输出观察项
    if (const CXXMethodDecl* cxxmd = dyn_cast<CXXMethodDecl>(func_decl)) {
      //      njson& outobj = testif["output"]["object"] = njson::object();
      /* outobj["@type"] =*/
      testif["@object"] = parse_cxxrecord_type(cxxmd->getParent());
    }
  }

  {
    // 异常
    // FIXME:异常应置于output中
    njson& fthrow = testif["output"]["exceptions"] = njson::array();

    map<const Type*, vector<Expr*> > throw_type_expr;
    for (auto& ft : target_func.throwexprs) {
      auto ft_expr = ft->getSubExpr();
      if (ft_expr) {
        throw_type_expr[ft_expr->getType().getTypePtr()].push_back(ft_expr);
      }
    }
    for (auto& ft : throw_type_expr) {
      njson info = njson::object();
      info["@type"] = parse_type(QualType(ft.first, 0));
      //      json &exprs = info["@exprs"] = json::array();
      //      for (auto &expr : ft.second) {
      //        exprs.push_back(common::getFullStmtStr(expr, ast));
      //      }
      fthrow.push_back(std::move(info));
    }
  }

  {  // 模板特化
    for (auto& specf : target_func.specfs) {
      parse_function_definition(specf.first, specf.second);
      testif["@templateSpecs"].push_back(getFullNDeclName(specf.first, true));
    }
  }

  {  // 使用的类的成员
    for (auto& member_expr : target_func.memberexprs) {
      parse_member_usage(member_expr, testif["@mangled"]);
    }
  }

  if (setting.analyze_local_vars) {
    // 局部变量数据
    nlohmann::json locals = nlohmann::json::object();
    for (auto decl_pair : target_func.locals_decls) {
      auto vd = decl_pair.first;
      auto vd_stmt = decl_pair.second;

      auto vd_j = nlohmann::json::object();
      vd_j["@type"] = parse_type(vd->getType());

      // 变量大小
      if (setting.analyze_locvar_size) {
        if (vd->getType()->isIncompleteType() ||
            vd->getType()->isDependentType() ||
            vd->getType()->isUndeducedType()) {
          vd_j["@size"] = "?";
        } else {
          vd_j["@size"] =
              to_string(CI->getASTContext().getTypeSize(vd->getType()));
        }
      }

      // 定义位置
      {
        njson begin = njson::object();
        PresumedLoc presumed_loc =
            CI->getASTContext().getSourceManager().getPresumedLoc(
                vd->getBeginLoc());
        begin["line"] = std::to_string(presumed_loc.getLine());
        begin["column"] = std::to_string(presumed_loc.getColumn());
        vd_j["location"]["begin"] = std::move(begin);
      }
      {
        njson end = njson::object();
        PresumedLoc presumed_loc =
            CI->getASTContext().getSourceManager().getPresumedLoc(
                vd->getEndLoc());
        end["line"] = std::to_string(presumed_loc.getLine());
        end["column"] = std::to_string(presumed_loc.getColumn());
        vd_j["location"]["end"] = std::move(end);
      }

      // 生命周期
      {
        njson begin = njson::object();
        PresumedLoc presumed_loc =
            CI->getASTContext().getSourceManager().getPresumedLoc(
                vd->getBeginLoc());
        begin["line"] = std::to_string(presumed_loc.getLine());
        begin["column"] = std::to_string(presumed_loc.getColumn());
        vd_j["lifetime"]["begin"] = std::move(begin);
      }
      {
        njson end = njson::object();
        const auto& vd_stmt_parent = CI->getASTContext().getParents(*vd_stmt);
        if (!vd_stmt_parent.empty()) {
          PresumedLoc presumed_loc =
              CI->getASTContext().getSourceManager().getPresumedLoc(
                  vd_stmt_parent.begin()->getSourceRange().getEnd());
          end["line"] = std::to_string(presumed_loc.getLine());
          end["column"] = std::to_string(presumed_loc.getColumn());
          vd_j["lifetime"]["end"] = std::move(end);
        }
      }

      locals[vd->getNameAsString()].push_back(vd_j);
    }

    if (!locals.empty()) {
      testif["variables"]["local"] = locals;
    }
  }

  for (auto stub_decl : stub_default_functions) {
    TargetFunction tf(stub_decl);
    TestIfVisitor tiv(CI->getASTContext(), tf, setting);
    // stub_decl->getDefinition()->dump();
    tiv.TraverseStmt(stub_decl->getBody());
    auto default_func_json = parse_function_definition(stub_decl, tf);
    for (auto dfj_stub_it = default_func_json["stubs"].begin(),
              dfj_stub_end = default_func_json["stubs"].end();
         dfj_stub_it != dfj_stub_end; dfj_stub_it++) {
      testif["stubs"][dfj_stub_it.key()] = dfj_stub_it.value();
    }
  }

  elementCallBack(testif);

  if (func_decl->getBeginLoc().isValid()) {
    current_file.pop_back();
  }

  return testif;
}

void rocket::testif::TestIfConsumer::parse_member_usage(
    clang::MemberExpr* me, std::string func_space) {
  if (!me) return;
  auto base = me->getBase();
  if (!base) return;

  if (base->getType().isNull()) return;
  auto type = base->getType().getCanonicalType();
  if (me->isArrow() && type->isPointerType()) type = type->getPointeeType();
  if (type.isNull()) return;

  auto base_rd = type->getAsRecordDecl();
  if (!base_rd) return;
  auto type_str = parse_type(type.getUnqualifiedType());

  if (auto field = dyn_cast<FieldDecl>(me->getMemberDecl())) {
    auto type_it = types_j.find(type_str);
    if (type_it == types_j.end()) return;
    auto fields_it = type_it->find("@fields");
    if (fields_it == type_it->end()) return;

    string field_name;
    if (isa<CXXRecordDecl>(base_rd)) {
      field_name = getFullNDeclName(field);
    } else {
      field_name = field->getNameAsString();
    }
    field_name = currectKeyString(field_name);

    auto field_it = fields_it->find(field_name);
    if (field_it == fields_it->end()) return;

    auto& field_j = (*field_it);
    field_j["@isUsed"] = 1;
    if (!func_space.empty()) {
      auto field_used_it = field_j.find("@usedFunc");
      if (field_used_it != field_j.end() && !field_used_it->empty()) {
        if (field_used_it->rbegin()->get<string>() != func_space) {
          field_used_it->push_back(func_space);
        }
      } else {
        field_j["@usedFunc"].push_back(func_space);
      }
    }
  }
}

void rocket::testif::TestIfConsumer::parse_crecord(const QualType& type,
                                                   nlohmann::json& j) {
  nlohmann::json attributes = nlohmann::json::array();

  attributes.push_back("isRecord");
  if (type->isStructureType()) {
    attributes.push_back("isStructure");
  } else if (type->isUnionType()) {
    attributes.push_back("isUnion");
  } else {
    throw std::runtime_error("Unsupported record type: " +
                             getFullIFTypeName(type, CI->getASTContext()));
  }

  const TagDecl* decl = type->getAsTagDecl();
  assert(decl != NULL);
  if (isAnonymous(decl)) attributes.push_back("isAnonymous");
  if (!decl->getDefinition()) attributes.push_back("isIncomplete");
  j["@attributes"] = std::move(attributes);

  nlohmann::json fields = nlohmann::json::object();
  const RecordDecl* record = type->getAsRecordDecl();
  for (auto field : record->fields()) {
    //    fields[field->getNameAsString()]["@type"] =
    //    parse_type(field->getType());
    std::string field_name = currectKeyString(field->getNameAsString());
    QualType field_type = field->getType();
    std::string type_name = parse_type(field_type);
    if (!field_name.empty()) {
      fields[std::move(field_name)]["@type"] = type_name;
    } else {
      if (field_type->isRecordType()) {
        auto& sub_fields = types_j[type_name]["@fields"];
        for (auto field_it = sub_fields.begin(); field_it != sub_fields.end();
             ++field_it) {
          fields.emplace(currectKeyString(field_it.key()), field_it.value());
        }
      }
    }
  }
  j["@fields"] = std::move(fields);
}

void rocket::testif::TestIfConsumer::parse_cxxrecord(const CXXRecordDecl* cxxrd,
                                                     const QualType& type,
                                                     nlohmann::json& j) {
  // 去除name中的模板部分，由属性值确定是否为模板，便于使用时拼接
  auto& cxxrd_name = j["@name"] = getNamedDeclName(cxxrd);

  nlohmann::json attributes = nlohmann::json::array();
  attributes.push_back("isCXXRecord");

  if (type.getTypePtrOrNull()) {
    if (type.isConstQualified()) attributes.push_back("isConst");
    if (isa<InjectedClassNameType>(type)) {
      attributes.push_back("isInjectedClass");
    }
    const TagDecl* decl = type->getAsTagDecl();
    assert(decl != NULL);
    if (isAnonymous(decl)) attributes.push_back("isAnonymous");
    if (!decl->getDefinition()) attributes.push_back("isIncomplete");
  }

  if (cxxrd->isStruct()) {
    attributes.push_back("isStructure");
  } else if (cxxrd->isUnion()) {
    attributes.push_back("isUnion");
  } else if (cxxrd->isClass()) {
    attributes.push_back("isClass");
  } else {
    throw std::runtime_error("Unsupported record type: " +
                             getFullIFTypeName(type, CI->getASTContext()));
  }

  {  // 类模板
    if (cxxrd->isTemplated()) {
      attributes.push_back("isTemplate");
      nlohmann::json template_args = nlohmann::json ::array();
      if (ClassTemplateDecl* ctd = cxxrd->getDescribedClassTemplate()) {
        // 模板形参
        j["@templateParms"] =
            parse_template_parms(ctd->getTemplateParameters());
        nlohmann::json specializations = nlohmann::json::array();
        for (CXXRecordDecl* spec_cxxrd : ctd->specializations()) {
          // specializations.push_back(
          //     parse_type(clang::QualType(spec_cxxrd->getTypeForDecl(),
          //     0)));
          specializations.push_back(parse_cxxrecord_type(spec_cxxrd));
        }
      }
    }

    if (const ClassTemplateSpecializationDecl* ctsd =
            dyn_cast<ClassTemplateSpecializationDecl>(cxxrd)) {
      // 模板实参
      attributes.push_back("isTemplateSpecialization");
      auto td = ctsd->getSpecializedTemplate()->getTemplatedDecl();
      string tempC_name = parse_cxxrecord_type(td);
      j["@template"] = tempC_name;  // 模板原型
      j["@templateArgs"] = parse_template_args(&ctsd->getTemplateArgs());
      cxxrd_name =
          getNamedDeclName(cxxrd) + common::getFullTempSpecArgsList(ctsd);

      auto tempC_it = types_j.find(tempC_name);
      if (tempC_it != types_j.end()) {
        if (tempC_it.value().count("@templateSpecs")) {
          tempC_it.value()["@templateSpecs"].push_back(
              parse_cxxrecord_type(cxxrd));
        } else {
          njson& specs = tempC_it.value()["@templateSpecs"] = njson::array();
          specs.push_back(parse_cxxrecord_type(cxxrd));
        }
      }
    }

    if (const ClassTemplatePartialSpecializationDecl* ctpsd =
            dyn_cast<ClassTemplatePartialSpecializationDecl>(cxxrd)) {
      // 部分特化
      attributes.push_back("isPartialSpecialzated");
      j["@templateParms"] =
          parse_template_parms(ctpsd->getTemplateParameters());
    }
  }

  {  // 类命名空间or边界
    nlohmann::json scopes = parse_scopes(cxxrd->getDeclContext());
    if (!scopes.empty()) {
      j["@scopes"] = std::move(scopes);
    }
  }

  {  // 类成员
    nlohmann::json fields = nlohmann::json::object();
    // auto bases = common::getAllRecordBases(cxxrd);
    // for (auto base : bases) {
    auto base = cxxrd;
    //    if (!base) continue;
    for (FieldDecl* field : base->fields()) {
      string field_name = currectKeyString(getFullNDeclName(field));
      QualType field_type = field->getType();
      std::string type_name = parse_type(field_type);

      if (!field_name.empty()) {
        nlohmann::json& field_json = fields[field_name];
        field_json["@type"] = type_name;
        if (field->isBitField())
          field_json["@bitwidth"] =
              field->getBitWidthValue(CI->getASTContext());
        field_json["@object"] = parse_type(QualType(base->getTypeForDecl(), 0));
      } else {
        if (field_type->isRecordType()) {
          auto& sub_fields = types_j[type_name]["@fields"];
          for (auto field_it = sub_fields.begin(); field_it != sub_fields.end();
               ++field_it) {
            fields.emplace(currectKeyString(field_it.key()), field_it.value());
          }
        }
      }
    }
    // }
    j["@fields"] = std::move(fields);
  }

  // 类继承
  if (const CXXRecordDecl* cxxrdd = cxxrd->getDefinition()) {
    nlohmann::json bases = nlohmann::json::array();
    for (auto base_decl : cxxrdd->bases()) {
      nlohmann::json base = nlohmann::json::object();
      std::string base_type_name = parse_type(base_decl.getType());
      base["@type"] = base_type_name;

      {
        // 派生类
        auto base_type_it = types_j.find(base_type_name);
        assert(base_type_it != types_j.end());
        // FIXME:生成名的步骤独立，不妥
        if (!type.isNull()) {
          string drived_name = parse_type(type);
          (*base_type_it)["@deriveds"].push_back(drived_name);
        }
      }

      switch (base_decl.getAccessSpecifier()) {
        case clang::AS_public:
          base["@access"].push_back("isPublic");
          break;
        case clang::AS_private:
          base["@access"].push_back("isPrivate");
          break;
        case clang::AS_protected:
          base["@access"].push_back("isProtected");
          break;
        case clang::AS_none:
          base["@access"].push_back("isNone");
          break;
      }
      if (base_decl.isVirtual()) {
        base["@access"].push_back("isVirtual");  // 虚继承
      }
      bases.push_back(std::move(base));
    }
    if (!bases.empty()) {
      attributes.push_back("isDervied");  // 派生类
      j["@bases"] = std::move(bases);
    }
  }

  nlohmann::json methods = nlohmann::json::array();
  nlohmann::json& constructors = j["@constructors"] = nlohmann::json::array();
  {  // 类方法
    for (CXXMethodDecl* method_decl : cxxrd->methods()) {
      if (CXXConstructorDecl* cxxconstr_decl =
              dyn_cast<CXXConstructorDecl>(method_decl)) {
        // 构造函数单独分出
        constructors.push_back(parse_function_method(cxxconstr_decl));
      } else {
        //        if (setting.should_analyze_full) {
        //          auto method_js = parse_function_method(method_decl);
        //          methods.push_back(std::move(method_js));
        //        }
      }
    }
  }

  //  {  // 模板方法
  //    if (setting.should_analyze_full) {
  //      auto ftd_method_range = llvm::iterator_range<
  //          DeclContext::specific_decl_iterator<FunctionTemplateDecl>>(
  //          cxxrd->decls());
  //      for (FunctionTemplateDecl* ftd : ftd_method_range) {
  //        auto func_decl_js =
  //        parse_function_declaration(ftd->getTemplatedDecl());
  //        methods.push_back(std::move(func_decl_js));
  //      }
  //    }
  //  }

  //  if (setting.should_analyze_full && !methods.empty()) {
  //    j["@methods"] = std::move(methods);
  //  }

  j["@attributes"] = std::move(attributes);
}

void rocket::testif::TestIfConsumer::parse_record(const QualType& type,
                                                  nlohmann::json& j) {
  if (RecordDecl* crecord = type->getAsRecordDecl()) {
    if (CXXRecordDecl* cxxrecord = dyn_cast<CXXRecordDecl>(crecord)) {
      parse_cxxrecord(cxxrecord, type, j);
    } else {
      parse_crecord(/*crecord,*/ type, j);
    }
  } else {
    throw std::runtime_error(type.getAsString() + " is not recod type");
  }
}

void rocket::testif::TestIfConsumer::parse_enum(const QualType& type,
                                                nlohmann::json& j) {
  nlohmann::json& attributes = j["@attributes"] = nlohmann::json::array();
  attributes.push_back("isEnumeral");

  const TagDecl* td = type->getAsTagDecl();
  if (const TagDecl* enum_def = td->getDefinition()) {
    const EnumDecl* ed = dyn_cast<EnumDecl>(enum_def);

    if (!ed) {
      attributes.push_back("isIncomplete");
      return;
    }

    // TODO: enums after C++11
    if (CI->getASTContext().getLangOpts().CPlusPlus) {
      //      nlohmann::json &value = j["@enums"] = nlohmann::json::array();
      //      for (const EnumConstantDecl *e : ed->enumerators()) {
      //        nlohmann::json enum_value = nlohmann::json::object();
      //        enum_value["@name"] = e->getNameAsString();
      //        enum_value["@type"] = parse_type(e->getType());
      //        enum_value["@value"] = to_string(e->getInitVal().getExtValue());
      //        value.push_back(std::move(enum_value));
      //      }
      nlohmann::json& value = j["@enums"] = nlohmann::json::object();
      for (auto&& item : ed->enumerators()) {
        value.emplace(common::getFullNDeclName(item),
                      item->getNameAsString() + "/* " +
                          std::to_string(item->getInitVal().getSExtValue()) +
                          " */");
      }
    } else {
      nlohmann::json& value = j["@enums"] = nlohmann::json::object();
      for (auto&& item : ed->enumerators()) {
        value.emplace(std::to_string(item->getInitVal().getSExtValue()),
                      item->getNameAsString());
      }
    }
  } else {
    attributes.push_back("isIncomplete");
  }
}

void rocket::testif::TestIfConsumer::parse_dependent_type(const QualType& type,
                                                          nlohmann::json& j) {
  j["@attributes"].push_back("isDependent");

  if (const DependentNameType* dnt = type->getAs<DependentNameType>()) {
    if (NestedNameSpecifier* nns = dnt->getQualifier()) {
      auto& nested_j = j["@nested"] = njson::array();
      do {
        if (auto nested_record = nns->getAsRecordDecl()) {
          njson nested_ele;
          nested_ele["@record"] =
              parse_type(QualType(nested_record->getTypeForDecl(), 0));
          nested_j.push_back(std::move(nested_ele));
        } else if (auto nested_type = nns->getAsType()) {
          // 为类型的待决名嵌套
          njson nested_ele;
          nested_ele["@type"] = parse_type(QualType(nested_type, 0));
          nested_j.push_back(std::move(nested_ele));
        } else if (auto nested_namespace = nns->getAsNamespace()) {
          njson nested_ele;
          nested_ele["@namespace"] = getFullNDeclName(nested_namespace);
          nested_j.push_back(std::move(nested_ele));
        }
        // else if (auto nested_namespace_alias = nns->getAsNamespace()) {
        // }
        // TODO: 嵌套待决名的其他情况

        nns = nns->getPrefix();
      } while (nns);
    }
  }

  return;
}

void rocket::testif::TestIfConsumer::parse_reference(const QualType& type,
                                                     nlohmann::json& j) {
  //  const clang::QualType nr_qt = type.getNonReferenceType();

  nlohmann::json attributes = nlohmann::json::array();
  attributes.push_back("isReference");
  if (type->isRValueReferenceType()) {
    attributes.push_back("isRValueReference");
  }
  if (type->isLValueReferenceType()) {
    attributes.push_back("isLValueReference");
  }
  j["@attributes"] = std::move(attributes);
  j["@pointeeType"] = parse_type(type.getNonReferenceType());
}

void rocket::testif::TestIfConsumer::parse_array(const QualType& type,
                                                 nlohmann::json& j) {
  const ArrayType* array_type = type->castAsArrayTypeUnsafe();
  assert(array_type != nullptr);

  int length;
  if (auto* ca = dyn_cast<const ConstantArrayType>(array_type)) {
    auto tmp = ca->getSize().getSExtValue();
    length = tmp;
  } else {
    length = 0;
  }

  std::string element_type_name = parse_type(array_type->getElementType());

  nlohmann::json attributes = nlohmann::json::array();
  attributes.push_back("isArray");
  //  if (type.isConstQualified()) attributes.push_back("isConst");
  j["@attributes"] = std::move(attributes);
  j["@elementType"] = element_type_name;
  j["@length"] = to_string(length);
}

void rocket::testif::TestIfConsumer::parse_pointer(const QualType& type,
                                                   nlohmann::json& j) {
  std::string pointee_type_name = parse_type(type->getPointeeType());

  nlohmann::json attributes = nlohmann::json::array();
  attributes.push_back("isPointer");
  if (type->isFunctionPointerType()) {
    attributes.push_back("isFunctionPointer");
  }
  if (type->isVoidPointerType()) {
    attributes.push_back("isVoidPointer");
  }
  //  if (type.isConstQualified()) attributes.push_back("isConst");
  j["@attributes"] = std::move(attributes);
  j["@pointeeType"] = pointee_type_name;
}

void rocket::testif::TestIfConsumer::parse_member_pointer(const QualType& type,
                                                          nlohmann::json& j) {
  if (type->isDependentType()) return;

  const MemberPointerType* mpt = dyn_cast<MemberPointerType>(type.getTypePtr());
  assert(mpt);
  const CXXRecordDecl* cxxrd = mpt->getMostRecentCXXRecordDecl();
  std::string pointee_type_name = parse_type(mpt->getPointeeType());
  j["@pointeeType"] = pointee_type_name;
  // j["@recordType"] = parse_type(clang::QualType(cxxrd->getTypeForDecl(),
  // 0));
  j["@recordType"] = parse_cxxrecord_type(cxxrd);

  nlohmann::json& attributes = j["@attributes"] = nlohmann::json::array();
  attributes.push_back("isMemberPointer");
  if (type->isMemberDataPointerType()) {
    attributes.push_back("isMemberDataPointer");
    nlohmann::json& possible_data = j["@data"] = nlohmann::json::array();
    for (auto field : cxxrd->fields()) {
      if (field->getType() == mpt->getPointeeType())
        possible_data.push_back(getFullNDeclName(field));
    }
  }
  if (type->isMemberFunctionPointerType()) {
    attributes.push_back("isMemberFunctionPointer");
    nlohmann::json& possible_func = j["@func"] = nlohmann::json::array();
    // TODO: 函数指针
    for (auto method : cxxrd->methods()) {
      if (method->getType() == mpt->getPointeeType()) {
        parse_function_method(method);
        possible_func.push_back(getFullNDeclName(method, true));
      }
    }
  }
}

static bool isPlaceHolderType(const BuiltinType* type) {
  switch (type->getKind()) {
#define BUILTIN_TYPE(ID, TYPE)
#define PLACEHOLDER_TYPE(ID, TYPE) case clang::BuiltinType::Kind::ID:
#include <clang/AST/BuiltinTypes.def>
    return true;
    default:
      break;
  }

  return false;
}

string rocket::testif::TestIfConsumer::parse_canonical_type(QualType type) {
  assert(type.isCanonical());

  // type.removeLocalVolatile();
  type.removeLocalRestrict();

  string type_name = getFullIFTypeName(type, CI->getASTContext());

  nlohmann::json::iterator type_it;
  bool ignore;
  std::tie(type_it, ignore) =
      types_j.emplace(type_name, nlohmann::json::object());

  // {
  //   auto type_path_it =
  //       type_it.value().emplace("@usedPaths", njson::array()).first;
  //   auto type2files_it =
  //       type2files_map.emplace(&type_path_it.value(),
  //       std::set<clang::FileID>{})
  //           .first;
  //   type2files_it->second.insert(current_file.begin(), current_file.end());
  // }

  if (!ignore) {
    return type_name;
  }

  nlohmann::json& j = type_it.value();

  if (type.isConstQualified()) {
    // 消除const限定作为原类型的一个属性
    std::string unqualified_name = parse_type(type.getUnqualifiedType());
    j["@canonical"] = type_name;
    j["@attributes"] = types_j[unqualified_name]["@attributes"];
    j["@attributes"].push_back("isConst");
    j["@unqualified"] = unqualified_name;
  } else if (type.isVolatileQualified()) {
    // 消除Volatile限定作为原类型的一个属性
    std::string unqualified_name = parse_type(type.getUnqualifiedType());
    j["@canonical"] = type_name;
    j["@attributes"] = types_j[unqualified_name]["@attributes"];
    j["@attributes"].push_back("isVolatile");
    j["@unqualified"] = unqualified_name;
  } else {
    j["@canonical"] = type_name;
    j["@unqualified"] = type_name;

    // 类型修饰
    if (type->isReferenceType()) {  // 引用
      parse_reference(type, j);
    } else if (type->isPointerType()) {  // 指针
      parse_pointer(type, j);
    } else if (type->isArrayType()) {  // 数组
      parse_array(type, j);
    } else if (type->isMemberPointerType()) {
      parse_member_pointer(type, j);
    } else if (type->isRecordType()) {  // class, union, struct
      parse_record(type, j);
    } else if (type->isEnumeralType()) {
      parse_enum(type, j);
    } else if (type->isFunctionType()) {  // 函数类型
      parse_function_type(type, j);
    } else if (type->isTemplateTypeParmType()) {  // 类型模板型参
      // 类型模板的形参转换为CanonicalType时会显示为type-parameter-0-0
      parse_template_type_parm(type, j);
    } else if (const Type* tp = type.getTypePtr()) {  // 其他
      if (const InjectedClassNameType* icnt =
              dyn_cast<InjectedClassNameType>(tp)) {
        // The injected class name of a C++ class template or class template
        // partial specialization.
        parse_cxxrecord(icnt->getDecl(), type, j);
      } else if (const TemplateSpecializationType* tst =
                     dyn_cast<TemplateSpecializationType>(tp)) {
        if (tst->isSugared()) {
          return parse_type(tst->desugar().getCanonicalType());
        } else if (tst->isTypeAlias()) {
          return parse_type(tst->getAliasedType().getCanonicalType());
        }
      } else {
        //**常规类型
        std::string type_name = getFullIFTypeName(type, CI->getASTContext());
        const TagDecl* decl = type->getAsTagDecl();

        // 内置
        nlohmann::json attributes = nlohmann::json::array();
        if (type->isVoidType()) attributes.push_back("isVoid");
        if (type->isEnumeralType()) {
          attributes.push_back("isEnumeral");
          assert(decl != NULL);
          EnumDecl* enum_decl = dynamic_cast<EnumDecl*>(decl->getDefinition());
          if (!enum_decl) {
            attributes.push_back("isIncomplete");
          } else {
            njson enums = njson::object();
            for (auto&& item : enum_decl->enumerators()) {
              enums.emplace(std::to_string(item->getInitVal().getSExtValue()),
                            getFullNDeclName(item));
            }
            j["@enums"] = std::move(enums);
          }
        }
        if (type->isBooleanType()) attributes.push_back("isBoolean");
        if (type->isCharType()) attributes.push_back("isChar");
        if (type->isIntegerType()) attributes.push_back("isInteger");
        if (type->isRealType()) attributes.push_back("isReal");
        if (type->isFloatingType()) attributes.push_back("isFloating");

        if (decl && !decl->getIdentifier() &&
            !decl->getTypedefNameForAnonDecl())
          attributes.push_back("isAnonymous");

        if (attributes.empty()) {
          attributes.push_back("isUnSupported:" +
                               string(type->getTypeClassName()));
        }

        j["@attributes"] = std::move(attributes);

        auto builtin_type_ptr = dyn_cast<BuiltinType>(type.getTypePtr());
        if (!type->isDependentType() && builtin_type_ptr) {
          unsigned int type_width;
          if (!isPlaceHolderType(builtin_type_ptr))
            j["@width"] = type_width =
                CI->getASTContext().getTypeInfo(builtin_type_ptr).Width;

          static const auto ptr_width =
              CI->getASTContext()
                  .getTypeInfo(CI->getASTContext().VoidPtrTy)
                  .Width;
          if (builtin_type_ptr->isIntegerType() && type_width == ptr_width) {
            j["@attributes"].push_back("isAsPointerAble");
          }

          bool is_unsigned = false;
          switch (builtin_type_ptr->getKind()) {
#define BUILTIN_TYPE(ID, TYPE)
#define UNSIGNED_TYPE(ID, TYPE)               \
  case clang::BuiltinType::Kind::ID: {        \
    j["@attributes"].push_back("isUnsigned"); \
    is_unsigned = true;                       \
    break;                                    \
  }
#define FLOATING_TYPE(ID, TYPE)           \
  case clang::BuiltinType::Kind::ID: {    \
    j["@attributes"].push_back("is" #ID); \
    break;                                \
  }
#include <clang/AST/BuiltinTypes.def>
            default:
              break;
          }

          string type_max;
          string type_min;

          if (builtin_type_ptr->isCharType()) {
            switch (type_width) {
              case 8: {
                if (is_unsigned) {
                  type_max = "255";
                  type_min = "0";
                } else {
                  type_max = "127";
                  type_min = "-128";
                }
                break;
              }
              case 16: {
                type_max = "65535";
                type_min = "0";
                break;
              }
              case 32: {
                type_max = "1114111";
                type_min = "0";
                break;
              }
            }
          } else if (builtin_type_ptr->isIntegerType()) {
            static const char* range_integer_signed_max[] = {
                "127" /*8*/, "32767" /*16*/, "2147483647" /*32*/,
                "9223372036854775807" /*64*/};
            static const char* range_integer_signed_min[] = {
                "-128" /*8*/, "-32768" /*16*/, "-2147483648" /*32*/,
                "-9223372036854775808" /*64*/
            };
            static const char* range_integer_unsigned_max[] = {
                "225" /*8*/, "65535" /*16*/, "4294967295 " /*32*/,
                "18446744073709551615" /*64*/};

            int bit_count = 0;
            switch (type_width) {
              case 8: {
                bit_count = 0;
                break;
              }
              case 16: {
                bit_count = 1;
                break;
              }
              case 32: {
                bit_count = 2;
                break;
              }
              case 64: {
                bit_count = 3;
                break;
              }
            }

            if (is_unsigned) {
              type_max = range_integer_unsigned_max[bit_count];
              type_min = "0";
            } else {
              type_max = range_integer_signed_max[bit_count];
              type_min = range_integer_signed_min[bit_count];
            }

          } else if (builtin_type_ptr->isFloatingType()) {
            static const char* range_floating[] = {
                "3.4028234e+38" /*32*/, "1.7976931348623157e+308" /*64*/};

            // TODO: opencl中的半精度half暂时以单精度float为准
            switch (type_width) {
              case 16:
              case 32: {
                type_max = range_floating[0];
                type_min = string("-") + range_floating[0];
                break;
              }
              case 64: {
                type_max = range_floating[1];
                type_min = string("-") + range_floating[1];
                break;
              }
            }
          }

          if (!type_max.empty() && !type_min.empty()) {
            auto& type_range = j["@range"] = njson::object();
            type_range["@max"] = type_max;
            type_range["@min"] = type_min;
          }
        }
      }
    }
  }

  if (type->isDependentType())
  // 若即不为上述类型但仍为待决名时的解析
  {
    // NOTE：待决名解析后置防止一部分模板声明被视作待决
    parse_dependent_type(type, j);
  }

  elementCallBack(j);

  return type_name;
}

void rocket::testif::TestIfConsumer::parse_fixed_addresses() {
  // 文件绝对地址
  njson fixed_address_bases = njson::object();
  njson fixed_address_types = njson::array();
  for (auto& base : fixedaddr_bases) {
    njson fixed_address = njson::object();
    {
      std::stringstream ss;
      ss << "0x" << std::hex << base.first;
      fixed_address["@hex"] = ss.str();
    }
    {
      fixed_address["@dec"] = to_string(base.first);
    }

    if (!setting.analyze_fixedaddr_offsets) {
      continue;
    }

    std::map<int64_t, QualType> offsets;
    for (auto& fixed_address_expr : base.second) {
      fixed_address["@exprs"].push_back(fixed_address_expr.first);
      auto& expr = fixed_address_expr.second;
      QualType type;
      if (expr.index == 0) {
        type = expr.pointee_type;
      } else {
        llvm::APInt ap_int(sizeof(expr.index) * CHAR_BIT, expr.index + 1);
#if LLVM_VERSION_MAJOR < 9
        type = CI->getASTContext().getConstantArrayType(
            expr.pointee_type, ap_int,
            clang::ArrayType::ArraySizeModifier::Normal, 0);
#elif LLVM_VERSION_MAJOR < 18
        type = CI->getASTContext().getConstantArrayType(
            expr.pointee_type, ap_int, nullptr,
            clang::ArrayType::ArraySizeModifier::Normal, 0);
#else
        type = CI->getASTContext().getConstantArrayType(
            expr.pointee_type, ap_int, nullptr, ArraySizeModifier::Normal, 0);
#endif
      }

      if (type.isNull()) {
        continue;
      }

      auto offset_it = offsets.find(expr.offset);
      if (offset_it == offsets.end()) {
        offsets.emplace(expr.offset, type);
      } else if (!offset_it->second.isNull() &&
                 CI->getASTContext().getTypeSize(offset_it->second) <
                     CI->getASTContext().getTypeSize(type)) {
        offset_it->second = type;
      }
      std::string type_name = parse_type(type);
      if (fixed_address_types.find(type_name) == fixed_address_types.end()) {
        fixed_address_types.push_back(type_name);
      }
    }

    njson pointer_targets = njson::object();
    for (auto& offset : offsets) {
      auto& type = offset.second;
      njson pointer_target = njson::object();
      pointer_target["@type"] = parse_type(type);
      if (type->isArrayType()) {
        const ArrayType* array_type = type->getAsArrayTypeUnsafe();
        pointer_target["@length"] =
            std::to_string(dyn_cast<clang::ConstantArrayType>(array_type)
                               ->getSize()
                               .getZExtValue());
        pointer_target["@elementType"] =
            parse_type(array_type->getElementType());
      }
      pointer_targets.emplace(std::to_string(offset.first), pointer_target);
    }
    if (pointer_targets.empty()) {
      njson pointer_target = njson::object();
      llvm::APInt ap_int(sizeof(unsigned) * CHAR_BIT, 1);
#if LLVM_VERSION_MAJOR < 9
      QualType type = CI->getASTContext().getConstantArrayType(
          CI->getASTContext().CharTy, ap_int,
          clang::ArrayType::ArraySizeModifier::Normal, 0);
#elif LLVM_VERSION_MAJOR < 18
      QualType type = CI->getASTContext().getConstantArrayType(
          CI->getASTContext().CharTy, ap_int, nullptr,
          clang::ArrayType::ArraySizeModifier::Normal, 0);
#else
      QualType type = CI->getASTContext().getConstantArrayType(
          CI->getASTContext().CharTy, ap_int, nullptr,
          ArraySizeModifier::Normal, 0);
#endif
      pointer_target["@type"] = parse_type(type);
      pointer_target["@length"] = "1";
      pointer_target["@elementType"] = parse_type(CI->getASTContext().CharTy);
      pointer_targets.emplace("0", pointer_target);
    }
    fixed_address["pointerTargets"] = std::move(pointer_targets);
    fixed_address_bases.emplace(std::to_string(base.first), fixed_address);
  }
  if (!fixed_address_bases.empty()) {
    std::string char_name = parse_type(CI->getASTContext().CharTy);
    if (fixed_address_types.find(char_name) == fixed_address_types.end()) {
      fixed_address_types.push_back(std::move(char_name));
    }
  }
  fixed_addresses_j.emplace("bases", std::move(fixed_address_bases));
  fixed_addresses_j.emplace("types", std::move(fixed_address_types));
}

nlohmann::json rocket::testif::TestIfConsumer::parse_fixed_address_exprs(
    const std::map<std::string, std::vector<rocket::share::FixedAddress> >&
        fixed_addresses,
    ASTContext& ast) {
  njson fixed_address_exprs = njson::object();
  for (auto& fixed_address : fixed_addresses) {
    njson fixed_address_parent = njson::object();
    std::string parent_string = fixed_address.first;
    // Make the json data of test interfaces compatible with mongodb.
    // boost::replace_all(parent_string, "$", "\uff04");
    // boost::replace_all(parent_string, ".", "\uff0e");
    auto fixed_address_it = fixed_address.second.begin();
    fixed_address_parent["@value"] = std::to_string(fixed_address_it->base);
    fixed_address_parent["@type"] = parse_type(fixed_address_it->type);
    fixed_address_parent["@pointeeType"] =
        parse_type(fixed_address_it->pointee_type);
    fixed_address_parent["@offset"] = std::to_string(fixed_address_it->offset);
    fixed_address_parent["@index"] = std::to_string(fixed_address_it->index);
    njson locations = njson::object();
    for (unsigned index = 0; fixed_address_it != fixed_address.second.end();
         ++fixed_address_it, ++index) {
      if (fixed_address_it->base != 0) {
        fixedaddr_bases[fixed_address_it->base].emplace(parent_string,
                                                        *fixed_address_it);
      }
      njson location = njson::object();
      location["@type"] = parse_type(fixed_address_it->type);
      location["@pointeeType"] = parse_type(fixed_address_it->pointee_type);
      {
        bool invalid = false;
        StringRef source = Lexer::getSourceText(
            CharSourceRange::getTokenRange(
                fixed_address_it->parent->getSourceRange()),
            ast.getSourceManager(), ast.getLangOpts(), &invalid);
        if (!invalid) {
          location["@expr"] = source;
        } else {
          location["@expr"] = parent_string;
        }
      }
      {
        bool invalid = false;
        StringRef source = Lexer::getSourceText(
            CharSourceRange::getTokenRange(
                fixed_address_it->expr->getSourceRange()),
            ast.getSourceManager(), ast.getLangOpts(), &invalid);
        if (!invalid) {
          location["@baseExpr"] = source;
        } else {
          std::string base_expr;
          llvm::raw_string_ostream os(base_expr);
          fixed_address_it->expr->printPretty(
              os, nullptr, PrintingPolicy(ast.getLangOpts()));
          os.flush();
          location["@baseExpr"] = std::move(base_expr);
        }
      }
      {
        njson begin = njson::object();
        PresumedLoc presumed_loc = ast.getSourceManager().getPresumedLoc(
            fixed_address_it->parent->getBeginLoc());
        begin["line"] = std::to_string(presumed_loc.getLine());
        begin["column"] = std::to_string(presumed_loc.getColumn());
        location["begin"] = std::move(begin);
      }
      {
        njson end = njson::object();
        PresumedLoc presumed_loc = ast.getSourceManager().getPresumedLoc(
            fixed_address_it->parent->getEndLoc());
        end["line"] = std::to_string(presumed_loc.getLine());
        end["column"] = std::to_string(presumed_loc.getColumn());
        location["end"] = std::move(end);
      }
      locations.emplace(std::to_string(index), std::move(location));
    }
    fixed_address_parent["locations"] = std::move(locations);
    fixed_address_exprs.emplace(std::move(parent_string),
                                std::move(fixed_address_parent));
  }
  return fixed_address_exprs;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_variable(
    VarDecl* vd, bool visit_definition) {
  nlohmann::json j;

  if (!vd) return j;

  auto vd_fst = vd->getFirstDecl() ? vd->getFirstDecl() : vd;

  // 全局变量的使用位置记录
  unsigned path_count = 0;
  for (auto vd_rd : vd->redecls()) {
    if (vd_rd->getBeginLoc().isValid()) {
      current_file.push_back(CI->getASTContext().getSourceManager().getFileID(
          vd_rd->getBeginLoc()));
      path_count++;
    }
  }

  // 全局变量的类型
  const QualType type = vd_fst->getType();
  // 若无初始值仅显示类型
  string type_name = parse_type(type);

  for (auto redecl : vd->redecls()) {
    auto redecl_type = redecl->getType();
    if (!redecl_type.isNull()) parse_type(redecl_type);
  }

  VarDecl* def = vd->getDefinition();

  if (def && def->hasInit() && !def->getDescribedVarTemplate()) {
    Expr* init = def->getInit();
    // 实际的值，若无初始值，则仅保留原名和类型，否则会在下方被覆盖。
    if ((!CI->getASTContext().getLangOpts().MSCompatibilityVersion ||
         def->isConstexpr()) &&
        ((!init->isValueDependent() &&
          init->isConstantInitializer(CI->getASTContext(),
                                      type->isReferenceType())) ||
         (CI->getASTContext().getLangOpts().CPlusPlus &&
          (!init->isValueDependent() &&
           init->isCXX11ConstantExpr(CI->getASTContext()))))) {
      const APValue* apvalue = def->evaluateValue();
      if (apvalue) {
        j = parse_apvalue(type, *apvalue);
      } else {
        j = parse_init_expr(type, init);
      }
    }

    // 提取代码，无法获得值的时候直接提取表达式
    bool invalid = false;
    StringRef source = Lexer::getSourceText(
        CharSourceRange::getTokenRange(init->getSourceRange()),
        CI->getASTContext().getSourceManager(),
        CI->getASTContext().getLangOpts(), &invalid);
    if (!invalid && source.str() != j["@value"]) {
      j["@expr"] = source;
    } else {
      std::string ss;
      llvm::raw_string_ostream os(ss);
      init->printPretty(os, nullptr,
                        PrintingPolicy(CI->getASTContext().getLangOpts()));
      if (os.str() != j["@value"]) j["@expr"] = std::move(os.str());
    }

    if (visit_definition) {
      // 提取在声明过程中使用的
      InnerGlobalVisitor inner_visitor(def->getASTContext());
      inner_visitor.TraverseDecl(def);

      {  // - 定义中使用的用户定义字面量
        nlohmann::json inner_udliteral = nlohmann::json::array();
        for (UserDefinedLiteral* udliteral : inner_visitor.udliteral_) {
          inner_udliteral.push_back(parse_init_udliteral_expr(udliteral));
        }
        if (!inner_udliteral.empty()) {
          j["udliterals"] = std::move(inner_udliteral);
        }
      }

      {  // - 定义中使用的全局变量
        nlohmann::json inner_globals = nlohmann::json::array();
        for (VarDecl* var : inner_visitor.globals_) {
          if (global_declarations.find(var) != global_declarations.end()) {
            inner_globals.push_back(getFullNDeclName(var));
          }
        }
        j["globals"] = std::move(inner_globals);
      }

      {  // - 定义中的函数调用
        nlohmann::json inner_stubs = nlohmann::json::object();
        for (FunctionDecl* func : inner_visitor.functions_) {
          if (func->isDefaulted() || isInExcludeNamespace(func)) continue;
          inner_stubs[getFullNDeclName(func, isCXX())] =
              parse_function_stub(func /*, true*/);

          if (isa<CXXMethodDecl>(func)) {
            auto decl_it = function_declarations.find(func->getFirstDecl());
            if (decl_it != function_declarations.end()) {
              for (auto stub_decl : decl_it->second.overridings) {
                string func_name = getFullNDeclName(stub_decl, isCXX());

                if (inner_stubs.find(func_name) != inner_stubs.end()) continue;
                inner_stubs[func_name] =
                    parse_function_stub(stub_decl /*, false*/);
              }
            }
          }
        }
        j["stubs"] = std::move(inner_stubs);
      }

      // 绝对地址
      {
        njson fixed_addrs = njson::object();
        fixed_addrs["exprs"] = parse_fixed_address_exprs(
            inner_visitor.fixed_addresses, CI->getASTContext());
        j["fixedAddrs"] = std::move(fixed_addrs);
      }

      // 成员变量的使用
      {
        for (auto& member_expr : inner_visitor.member_exprs) {
          parse_member_usage(member_expr);
        }
      }
    }
  }

  if (def) {
    type_name = parse_type(def->getType());
    njson location = njson::object();
    {
      njson begin = njson::object();
      PresumedLoc presumed_loc =
          CI->getASTContext().getSourceManager().getPresumedLoc(
              def->getLocation());
      begin["line"] = std::to_string(presumed_loc.getLine());
      begin["column"] = std::to_string(presumed_loc.getColumn());
      location["begin"] = std::move(begin);
      if (setting.analyze_level !=
          share::RocketAnalyzeSetting::AnalyzeLevel::AL_Local) {
        auto loc_key = getLocation2Key(def);
        location["path"] = loc_key.first;
        location["isInProjectFile"] = loc_key.second;
        location["isInMainFile"] =
            CI->getASTContext().getSourceManager().isInMainFile(
                def->getLocation());
      }

      njson end = njson::object();
      end["line"] = std::to_string(presumed_loc.getLine());
      end["column"] = std::to_string(presumed_loc.getColumn() +
                                     def->getIdentifier()->getLength() - 1);
      location["end"] = std::move(end);
    }
    j["location"] = std::move(location);
  }
  njson attributes = njson::array();
  if (vd->hasExternalFormalLinkage()) {
    attributes.push_back("isExtern");
  }
  if (vd->getStorageClass() == StorageClass::SC_Static) {
    if (vd->isStaticDataMember()) {
      attributes.push_back("isStaticDataMember");
    } else {
      attributes.push_back("isStatic");
    }
  }
  if (vd->getDefinition() || vd->hasDefinition()) {
    attributes.push_back("isDefined");
  }
  j["@attributes"] = std::move(attributes);

  // 边界
  {
    nlohmann::json scopes = parse_scopes(vd->getDeclContext());
    if (!scopes.empty()) {
      j["@scopes"] = std::move(scopes);
    }
  }

  j["@name"] = vd->getNameAsString();
  j["@fullname"] = getFullNDeclName(vd);
  j["@mangled"] = getFullNDeclName(vd, true);
  j["@type"] = type_name;

  elementCallBack(j);
  common::removeNullValues(j);

  // 全局变量的使用位置记录弹出
  while (path_count != 0 && !current_file.empty()) {
    current_file.pop_back();
    path_count--;
  }

  return j;
}

string rocket::testif::TestIfConsumer::parse_cxxrecord_type(
    const CXXRecordDecl* cxxrd) {
  if (!cxxrd->isTemplated() || isa<ClassTemplateSpecializationDecl>(cxxrd)) {
    QualType qt = QualType(cxxrd->getTypeForDecl(), 0);
    return parse_type(qt);
  }

  string temp_name = getFullNDeclName(cxxrd);

  if (types_j.find(temp_name) != types_j.end()) return temp_name;

  nlohmann::json::iterator type_it;
  bool ignore;
  std::tie(type_it, ignore) =
      types_j.emplace(temp_name, nlohmann::json::object());
  assert(ignore == true);
  nlohmann::json& j = type_it.value();

  parse_cxxrecord(cxxrd, QualType(), j);

  elementCallBack(j);
  return temp_name;
}

// parse_type入口
string rocket::testif::TestIfConsumer::parse_type(const QualType& qtype) {
  if (qtype.isCanonical()) {
    return parse_canonical_type(qtype.getCanonicalType());
  }

  clang::QualType type_tmp = qtype;
  type_tmp.removeLocalRestrict();
  // type_tmp.removeLocalVolatile();
  std::string type_name = getFullIFTypeName(type_tmp, CI->getASTContext());
  std::string canonical_name =
      parse_canonical_type(type_tmp.getCanonicalType());

  nlohmann::json::iterator type_it;
  bool ignore;
  std::tie(type_it, ignore) = types_j.emplace(type_name, njson::object());

  // 添加现环境的路径
  // {
  //   auto type_path_it =
  //       type_it.value().emplace("@usedPaths", njson::array()).first;
  //   auto type2files_it =
  //       type2files_map.emplace(&type_path_it.value(),
  //       std::set<clang::FileID>{})
  //           .first;
  //   type2files_it->second.insert(current_file.begin(), current_file.end());
  // }

  if (!ignore) return type_name;
  njson& j = type_it.value();

  j["@canonical"] = canonical_name;
  j["@attributes"] = types_j[canonical_name]["@attributes"];
  j["@attributes"].push_back("isNonCanonical");
  if (const auto* typedef_type = dyn_cast<TypedefType>(type_tmp.getTypePtr())) {
    j["@attributes"].push_back("isTypedef");
    j["@alias"] = parse_type(typedef_type->desugar());
  } else if (type_tmp->isFunctionType()) {
    parse_function_type(type_tmp, j);
  } else if (auto decay_type = dyn_cast<DecayedType>(type_tmp.getTypePtr())) {
    parse_type(decay_type->getOriginalType());
    parse_pointer(type_tmp, j);
  } else if (isa<PointerType>(type_tmp.getTypePtr())) {
    parse_pointer(type_tmp, j);
  } else if (isa<ArrayType>(type_tmp.getTypePtr())) {
    parse_array(type_tmp, j);
  }
  if (type_tmp.isLocalConstQualified()) {
    type_tmp.removeLocalConst();
    j["@unqualified"] = parse_type(type_tmp);
  } else {
    j["@unqualified"] = types_j[canonical_name]["@unqualified"];
  }
  types_j[canonical_name]["@non-canonicals"].push_back(type_name);

  if (isCXX() && isa<ElaboratedType>(qtype.getTypePtrOrNull()) &&
      qtype->isRecordType()) {
    return canonical_name;
  }

  return type_name;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_template_args(
    const TemplateArgumentList* ta_list) {
  if (ta_list == nullptr) {
    return nlohmann::json::array();
  }

  nlohmann::json template_args = nlohmann::json::array();
  for (const TemplateArgument& ta : ta_list->asArray()) {
    template_args.push_back(parse_template_arg(ta));
  }
  return template_args;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_apvalue(
    const QualType& type_, const APValue& apvalue) {
  clang::QualType type = type_.getCanonicalType();
  type.removeLocalRestrict();
  // type.removeLocalVolatile();

  nlohmann::json j = nlohmann::json::object();
  std::string type_name = parse_type(type);

  if (types_j.find(type_name) == types_j.end()) {
    throw type_name;
  }

  j["@type"] = type_name;

  switch (apvalue.getKind()) {
#if LLVM_VERSION_MAJOR >= 9
    case APValue::ValueKind::None:  // 无类型， 初始状态，不会出现 llvm 9,
                                    // 原为Uninitialized
#else
    case APValue::ValueKind::Uninitialized:
#endif
      throw "Unsupported APValue: Uninitialized";
      break;

#if LLVM_VERSION_MAJOR >= 9
    case APValue::ValueKind::Indeterminate:  // 模糊类型，llvm 9新增
      throw "Unsupported APValue: Indeterminate";
      break;
    case APValue::ValueKind::FixedPoint:  // 定点数，llvm9新增
      throw "Unsupported APValue: FixedPoint";
      break;
#endif

    case APValue::ValueKind::Int:  // 普通int
    {
      // clang - toString(Radix) is an inefficient method
#if LLVM_VERSION_MAJOR < 13
      j["@value"] = apvalue.getInt().toString(10);
#else
      SmallString<10> S;
      apvalue.getInt().toString(S, 10);
      j["@value"] = S.str().str();
#endif
      break;
    }
    case APValue::ValueKind::Float:  // 普通float
    {
      auto type_ptr = dyn_cast<BuiltinType>(type.getTypePtr());
      if (type_ptr && type_ptr->getKind() == BuiltinType::Kind::Double) {
        j["@value"] = to_string(apvalue.getFloat().convertToDouble());
      } else {
        j["@value"] = to_string(apvalue.getFloat().convertToFloat());
      }
      break;
    }
    case APValue::ValueKind::ComplexInt:  // 复整型，c99
    {
      // clang - toString(Radix) is an inefficient method
      nlohmann::json val = nlohmann::json::object();
#if LLVM_VERSION_MAJOR < 13
      val["@real"] = apvalue.getComplexIntReal().toString(10);
      val["@imag"] = apvalue.getComplexIntImag().toString(10);
#else
      SmallString<10> S_real, S_imag;
      apvalue.getComplexIntReal().toString(S_real, 10);
      apvalue.getComplexIntImag().toString(S_imag, 10);
      val["@real"] = S_real.str().str();
      val["@imag"] = S_imag.str().str();
#endif
      j["@value"] = std::move(val);
      break;
    }
    case APValue::ValueKind::ComplexFloat:  // 复浮点，c99
    {
      nlohmann::json val = nlohmann::json::object();
      val["@real"] = to_string(apvalue.getComplexFloatReal().convertToFloat());
      val["@imag"] = to_string(apvalue.getComplexFloatImag().convertToFloat());
      j["@value"] = std::move(val);
      break;
    }

    case APValue::ValueKind::LValue:  // 左值表达式
    {
      if (const Expr* e = apvalue.getLValueBase().dyn_cast<const Expr*>()) {
        if (const StringLiteral* sl =
                dyn_cast<StringLiteral>(e->IgnoreParenCasts())) {
          // 字符串字面量
          if (type->isScalarType()) {
            // scalar type基本类型，包括：
            //  buildin（如int，float，char ...）
            //  enum（被定义的才能被称为scalar type）
            //  各类指针pointer
            //  c99 complex类型
            assert(type->isPointerType());  // 字符串字面量一定表现为指针类型
            std::string name =
                "string literal (at " +
                source_location_string(CI->getASTContext().getSourceManager(),
                                       sl->getBeginLoc()) +
                ")";  // 确保唯一性
            clang::QualType type = sl->getType();
            std::string type_name = parse_type(type);

            // 字符串字面量的初始化
            nlohmann::json value =
                parse_init_string_literal(type, sl, type_name);

            // 直接保存源代码格式的内容
            bool invalid = false;
            StringRef source = Lexer::getSourceText(
                CharSourceRange::getTokenRange(sl->getSourceRange()),
                CI->getASTContext().getSourceManager(),
                CI->getASTContext().getLangOpts(), &invalid);
            if (!invalid) value["@expr"] = source;
            elementCallBack(value);
            // boost::replace_all(name, "$", "\uff04");
            // boost::replace_all(name, ".", "\uff0e");
            literals_j[name] = value;
            j["@value"] =
                "#" + name + "@" +
                std::to_string(apvalue.getLValueOffset().getQuantity());
            return j;
          } else {
            // 不明复合类型时直接记录为string类型
            assert(type->isArrayType());
            return parse_init_string_literal(type, sl, type_name);
          }
        }
      }
      j["@value"] = apvalue.getAsString(CI->getASTContext(), type);
      break;
    }
    case APValue::ValueKind::Vector:  // NOTE: what is vector？？？
    {
      const ArrayType* array_type = type->getAsArrayTypeUnsafe();
      if (array_type == nullptr) break;

      j["@length"] = apvalue.getVectorLength();

      nlohmann::json elts = nlohmann::json::array();
      for (unsigned i = 0; i < apvalue.getVectorLength(); ++i) {
        const clang::APValue& vector_elt = apvalue.getVectorElt(i);
        elts.push_back(parse_apvalue(array_type->getElementType(), vector_elt));
      }
      j["@value"] = std::move(elts);
      break;
    }
    case APValue::ValueKind::Array:  // 数组
    {
      // 数组元素
      const ArrayType* array_type = type->getAsArrayTypeUnsafe();
      if (array_type == nullptr) break;
      unsigned length;
      if (const ConstantArrayType* ca =
              dyn_cast<ConstantArrayType>(array_type)) {
        length = ca->getSize().getSExtValue();
      } else {
        length = apvalue.getArraySize();
      }
      j["@length"] = length;
      j["@value"] = parse_apvalue_array(array_type, apvalue);

      break;
    }
    case APValue::ValueKind::Struct:  // 结构体
    {
      const RecordDecl* record = type->getAsRecordDecl();
      if (record) j["@value"] = parse_apvalue_struct(record, apvalue);
      break;
    }
    case APValue::ValueKind::Union:  // 联合体
    {
      assert(type->isUnionType());
      j["@value"] = parse_apvalue_union(apvalue);
      break;
    }
    case APValue::ValueKind::MemberPointer:  // 成员指针
    {
      assert(type->isMemberPointerType());
      j["@value"] = parse_apvalue_member_pointer(apvalue);
      break;
    }
    case APValue::ValueKind::AddrLabelDiff:;  // goto [label] ?
      {
        bool invalid;
        StringRef source = Lexer::getSourceText(
            CharSourceRange::getTokenRange(
                apvalue.getAddrLabelDiffLHS()->getLabel()->getSourceRange()),
            CI->getASTContext().getSourceManager(),
            CI->getASTContext().getLangOpts(), &invalid);
        if (!invalid) j["@value"] = source;
        break;
      }
  }

  return j;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_init_list_expr(
    const QualType& type_, const InitListExpr* ile) {
  clang::QualType type = type_.getCanonicalType();
  type.removeLocalRestrict();
  // type.removeLocalVolatile();

  if (!ile->isSemanticForm()) ile = ile->getSemanticForm();
  assert(ile != NULL);
  if (ile->isTransparent()) {
    return parse_init_expr(type, ile->getInit(0));
  }
  assert(!type->isScalarType());
  nlohmann::json j;

  std::string type_name = getFullIFTypeName(type, CI->getASTContext());
  assert(types_j.find(type_name) != types_j.end());
  j["@type"] = type_name;
  if (type->isRecordType()) {
    j["@value"] = parse_init_list_struct(type->getAsRecordDecl(), ile);
  } else if (type->isUnionType()) {
    j["@value"] = parse_init_list_union(/*type->getAsRecordDecl(),*/ ile);
  } else if (type->isArrayType()) {
    const ArrayType* array_type = type->getAsArrayTypeUnsafe();
    assert(array_type != NULL);
    unsigned length;
    if (auto* ca = dyn_cast<const ConstantArrayType>(array_type)) {
      length = ca->getSize().getSExtValue();
    } else {
      length = ile->getNumInits();
    }
    j["@length"] = length;
    j["@value"] = parse_init_list_array(array_type, ile);
  } else if (type->isDependentType()) {
    // TODO: 待决名
    //    cout << setw(4) << j << endl;
  } else {
    //    bool invalid = false;
    //    StringRef source = Lexer::getSourceText(
    //        CharSourceRange::getTokenRange(ile->getSourceRange()),
    //        CI->getASTContext().getSourceManager(),
    //        CI->getASTContext().getLangOpts(), &invalid);
    //    throw std::runtime_error(
    //        std::string("Unsupported type of initial list expression: ")
    //            .append(invalid ? "" : (std::string)source)
    //            .append(", with type:")
    //            .append(type.getAsString())
    //            .append(", at: ")
    //            .append(source_location_string(
    //                CI->getASTContext().getSourceManager(),
    //                ile->getBeginLoc())));
  }
  return j;
}

nlohmann::json rocket::testif::TestIfConsumer::parse_init_expr(
    const QualType& type_, const Expr* init) {
  clang::QualType type = type_.getCanonicalType();
  type.removeLocalRestrict();
  // type.removeLocalVolatile();

  // Step over an ArrayToPointerDecay implicit cCI->getASTContext().
  init = init->IgnoreParenCasts();

  /* 列表初始化 */
  if (const clang::InitListExpr* ile = dyn_cast<InitListExpr>(init)) {
    return parse_init_list_expr(type, ile);
  }

  Expr::EvalResult result;

  if (!init->isValueDependent() &&
      init->EvaluateAsRValue(result, CI->getASTContext())) {
    return parse_apvalue(type, result.Val);
  } else if (!init->isValueDependent() &&
             init->EvaluateAsLValue(result, CI->getASTContext())) {
    assert(result.isGlobalLValue());
    njson j;
    std::string type_name = parse_type(type);
    j["@type"] = type_name;
    if (const Expr* e = result.Val.getLValueBase().dyn_cast<const Expr*>()) {
      if (const StringLiteral* sl =
              dyn_cast<StringLiteral>(e->IgnoreParenCasts())) {
        if (type->isScalarType()) {
          assert(type->isPointerType());
          std::string name =
              "string literal (at " +
              source_location_string(CI->getASTContext().getSourceManager(),
                                     sl->getBeginLoc()) +
              ")";
          name = currectKeyString(name);
          QualType type = sl->getType();
          std::string type_name = parse_type(type);
          njson value =
              parse_init_string_literal(type, sl, type_name);  // 字符串字面量
          bool invalid = false;
          StringRef source = Lexer::getSourceText(
              CharSourceRange::getTokenRange(sl->getSourceRange()),
              CI->getASTContext().getSourceManager(),
              CI->getASTContext().getLangOpts(), &invalid);
          if (!invalid) value["@expr"] = source;
          literals_j[name] = value;
          j["@value"] =
              "#" + name + "@" +
              std::to_string(result.Val.getLValueOffset().getQuantity());
          return j;
        } else {
          assert(type->isArrayType());
          return parse_init_string_literal(type, sl, type_name);
        }
      } else {
        // TODO:
      }
    }
    string value = result.Val.getAsString(CI->getASTContext(), type);
    j["@value"] = std::move(value);
    return j;
  }

  nlohmann::json j;
  j["@type"] = parse_type(type);

  if (const CXXConstructExpr* cxxce = dyn_cast<CXXConstructExpr>(init)) {
    switch (cxxce->getConstructionKind()) {
#if LLVM_VERSION_MAJOR < 18
      case CXXConstructExpr::ConstructionKind::CK_Complete:
#else
      case CXXConstructionKind::Complete:
#endif
      {
        j["@kind"] = "CompleteConstruction";
        break;
      }
#if LLVM_VERSION_MAJOR < 18
      case CXXConstructExpr::ConstructionKind::CK_NonVirtualBase:
#else
      case CXXConstructionKind::NonVirtualBase:
#endif
      {
        j["@kind"] = "NonVirtualBaseConstruction";  // 非虚基类构造函数
        break;
      }
#if LLVM_VERSION_MAJOR < 18
      case CXXConstructExpr::ConstructionKind::CK_VirtualBase:
#else
      case CXXConstructionKind::VirtualBase:
#endif
      {
        j["@kind"] = "VirtualBaseConstruction";  // 虚基类构造函数
        break;
      }
#if LLVM_VERSION_MAJOR < 18
      case CXXConstructExpr::ConstructionKind::CK_Delegating:
#else
      case CXXConstructionKind::Delegating:
#endif
      {
        j["@kind"] = "DelegatingConstruction";  // 委托构造函数
        break;
      }
      default:
        break;
    }

    CXXConstructorDecl* cxxcd = cxxce->getConstructor();
    j["@mangled"] = getFullNDeclName(cxxcd, true);

    {
      nlohmann::json args = nlohmann::json::array();
      auto cxxcd_it = cxxcd->param_begin();
      for (unsigned int i = 0;
           i < cxxce->getNumArgs() && cxxcd_it != cxxcd->param_end();
           ++i, ++cxxcd_it) {
        const clang::Expr* e = cxxce->getArg(i);
        nlohmann::json arg = parse_init_expr(e->getType(), e);
        arg["@name"] = getFullNDeclName(*cxxcd_it);
        args.push_back(std::move(arg));
      }
      if (!args.empty()) j["@args"] = std::move(args);
    }

    return j;
  } else if (const CXXDefaultArgExpr* cxxdae =
                 dyn_cast<CXXDefaultArgExpr>(init)) {
    const clang::Expr* expr = cxxdae->getExpr();
    return parse_init_expr(expr->getType(), expr);
  } else if (const ImplicitCastExpr* ice = dyn_cast<ImplicitCastExpr>(init)) {
    const clang::Expr* expr = ice->getSubExpr();
    j = parse_init_expr(expr->getType(), expr);
    return j;
  } else if (const CXXBindTemporaryExpr* cxxbte =
                 dyn_cast<CXXBindTemporaryExpr>(init)) {
    // c++11
    // Represents binding an expression to a temporary.
    // This ensures the destructor is called for the temporary. It should only
    // be needed for non-POD, non-trivially destructable class types.
    const clang::Expr* expr = cxxbte->getSubExpr();
    j = parse_init_expr(expr->getType(), expr);
    return j;
  }

  if (isa<ImplicitValueInitExpr>(init)) return j;

  bool invalid = false;
  StringRef src = Lexer::getSourceText(
      CharSourceRange::getTokenRange(init->getSourceRange()),
      CI->getASTContext().getSourceManager(), CI->getASTContext().getLangOpts(),
      &invalid);
  if (!invalid) {
    j["@value"] = src;
    return j;
  }

  std::string ss;
  llvm::raw_string_ostream os(ss);
  init->printPretty(os, nullptr,
                    PrintingPolicy(CI->getASTContext().getLangOpts()));
  j["@value"] = std::move(os.str());

  return j;
}
